I'm fairly new to C++ and this is the problem I have:
I have two classes, Client
and Host
. And when everything is loaded you have the option to press two buttons, if you press button 1 Client
is loaded and if you press button 2 Host
is loaded.
Now both Client
and Host
are fairly big classes, and I don't want to put them both into the memory. So my idea was creating a Base
class, and then both Client
and Host
should extend the base class, and then the only thing I had to do was this:
Base connection;
//If button 1 is pressed:
connection = Client();
//If button 2 is pressed:
connection = Host();
Well this sounded almost too good to be true, and when I tried it I got no errors. Now comes the problem, Base
has a function called A
, and Client
has a function called B
. So the function B
is unique to the class Client
.
When I try to call function B
I get this error: 'class Base' has no member named 'B'
. How can I let C++ know that I am talking to class Client
or Host
instead of Base
? I am also open for a whole new approach to this problem. Maybe it's just an error in my thinking process.
Thanks in advance!
However, we can forcefully cast a parent to a child which is known as downcasting. After we define this type of casting explicitly, the compiler checks in the background if this type of casting is possible or not. If it's not possible, the compiler throws a ClassCastException.
This will work because we have cast parent to child and then child to sibling. Parent parent = new Child(); //Assigning child object to parent ref. variable. parent = new Sibling(); // Assigning sibling object to parent.
The parent class can hold reference to both the parent and child objects. If a parent class variable holds reference of the child class, and the value is present in both the classes, in general, the reference belongs to the parent class variable.
Classes called child classes or subclasses inherit methods and variables from parent classes or base classes. We can think of a parent class called Parent that has class variables for last_name , height , and eye_color that the child class Child will inherit from the Parent .
You ran into a situation which we call object slicing, which is a common problem in languages with value semantics such as C++.
Object slicing happens when you assign a value of a sub-type to a new location (your variable connection
) of a super type. This introduces a new copy of the instance, but of the super type, not the sub-type, so you lose the information about the concrete class you wanted to instantiate.
To avoid this, you have multiple options.
The classical approach uses pointers:
Base * connection;
connection = new YourConcreteType();
Then, to use this object, you have to derefrerence it using the asterisk operator (*
):
(*connection).function();
connection->function(); // syntactic sugar, semantically equivalent
Not to forget: You have to delete the object after usage:
delete connection;
To simplify this, C++ introduces two concepts: references and smart pointers. While the former has a restriction to be only assigned once, it is the syntactically simplest one. The latter is similar to the pointer approach, but you don't have to care about deletion, so you less likely run into a memory leak situation:
std::shared_ptr<Base> connection;
connection = make_shared<YourConcreteType>(); // construction via 'make_shared'
// ... use as if it were just a pointer ...
connection->function();
// no delete!
There are also other "smart pointer" types, like unique_ptr
, which can be used if you do not intend to pass the pointer around (if it stays in scope).
Now, you can implement the functions in both classes separately. To make use of polymorphism, this means, during runtime, either the function of the one subclass or of the other subclass is called, depending on which one was constructed, you should declare the functions in the base class as being virtual
, otherwise, the function definition in Base
will be called, regardless of the concrete type you have constructed.
In your case, you want to call a function which should do something different, depending on the type. While your approach was to introduce two different functions, namely A
and B
, you can just declare a single function, let's call it handleEvent
, as a pure virtual (= abstract) function in the base class, which means "this function is to be implemented in sub classes", and define it in the two subclasses independently:
Base {
....
virtual void handleEvent(...) = 0; // "= 0" means "pure"
};
// Don't provide an implementation
Client {
void handleEvent(...); // override it
};
// define it for Client:
void Client::handleEvent(...) {
...
}
Host {
void handleEvent(...); // override it
};
// define it for Host:
void Host::handleEvent(...) {
...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With