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(...) {
...
}