オブジェクトスライシングと呼ばれる状況に遭遇しました。これは、 C++などの値セマンティクスを持つ言語で一般的な問題です。
オブジェクトのスライスは、サブタイプの値をconnection
スーパータイプの新しい場所(変数)に割り当てるときに発生します。これにより、インスタンスの新しいコピーが導入されますが、サブタイプではなくスーパータイプであるため、インスタンス化する具体的なクラスに関する情報が失われます。
これを回避するには、複数のオプションがあります。
古典的なアプローチはポインタを使用します:
Base * connection;
connection = new YourConcreteType();
次に、このオブジェクトを使用するには、アスタリスク演算子()を使用して参照を解除する必要があります。*
(*connection).function();
connection->function(); // syntactic sugar, semantically equivalent
忘れないでください:使用後にオブジェクトを削除する必要があります:
delete connection;
これを単純化するために、C++では参照とスマートポインターという2つの概念が導入されています。前者には1回だけ割り当てるという制限がありますが、構文的に最も単純なものです。後者はポインタアプローチに似ていますが、削除を気にする必要がないため、メモリリークの状況に遭遇する可能性は低くなります。
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!
のような他の「スマートポインタ」タイプもありますunique_ptr
。これは、ポインタを渡すつもりがない場合(スコープ内にある場合)に使用できます。
これで、両方のクラスの関数を別々に実装できます。ポリモーフィズムを利用するには、実行時に一方のサブクラスまたはもう一方のサブクラスの関数が呼び出されます。どちらが作成されたかに応じて、基本クラスの関数を宣言する必要がありますvirtual
。そうでない場合は、関数Base
作成した具体的なタイプに関係なく、の定義が呼び出されます。
あなたの場合、タイプに応じて何か違うことをするはずの関数を呼び出したいと思います。あなたのアプローチは2つの異なる関数、つまりA
とを導入することでしたが、基本クラスの純粋な仮想(=抽象)関数としてB
単一の関数を宣言することができます。つまり、 「この関数はサブで実装されます。クラス」、および2つのサブクラスで独立して定義します。handleEvent
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(...) {
...
}