他に何もすることはありません。あなたが提供するコードはまさにそれを行います。
基本クラスへのポインタを取得すると、メソッドは基本クラスで宣言されており、仮想であるため、実際の実装はクラス仮想関数テーブルで検索され、適切に呼び出されます。
それで
base* base_ptr = new A();
base_ptr->get();
A :: get()を呼び出します。実装からnullを返さないでください(nullはstd :: list <something>に変換できないため、返すことはできません)。基本クラスのメソッドは純粋な仮想として宣言されているため、A/Bで実装を提供する必要があります。
編集:
Bも基本クラスを継承し、基本クラスには派生クラスでオーバーライドする必要がある純粋仮想メソッドがあるため、Aだけがstd :: list <something>を返し、Bは返さないようにすることはできません。基本クラスからの継承は「is-a」関係です。私が見ることができた他の唯一の方法は、クラスからプライベートに継承することですが、それは派生からベースへの変換を妨げるでしょう。
Bにgetメソッドを持たせたくない場合は、baseから継承しないでください。いくつかの選択肢は次のとおりです。
B :: get()で例外をスローする:B :: get()
で例外をスローすることもできますが、直感に反するため、論理的根拠を十分に説明してください。私見これはかなり悪い設計であり、基本クラスを使用している人々を混乱させるリスクがあります。これはリークの多い抽象化であり、避けるのが最善です。
個別のインターフェース:
ベースを個別のインターフェースに分割することができます:
class IGetSomething
{
public:
virtual ~IGetSomething() {}
virtual std::list<something> Get() = 0;
};
class base
{
public:
// ...
};
class A : public base, public IGetSomething
{
public:
virtual std::list<something> Get()
{
// Implementation
return std::list<something>();
}
};
class B : public base
{
};
IGetSomethingは純粋なインターフェイスであるため、この場合の多重継承は問題ありません(メンバー変数や非純粋なメソッドはありません)。
EDIT2:
コメントに基づくと、2つのクラス間で共通のインターフェースを持ちながら、一方の実装が実行する操作を実行できるようにしたいようですが、もう一方は提供しません。これはかなり複雑なシナリオですが、COMからインスピレーションを得ることができます(まだ私を撃たないでください):
class base
{
public:
virtual ~base() {}
// ... common interface
// TODO: give me a better name
virtual IGetSomething *GetSomething() = 0;
};
class A : public Base
{
public:
virtual IGetSomething *GetSomething()
{
return NULL;
}
};
class B : public Base, public IGetSomething
{
public:
virtual IGetSomething *GetSomething()
{
// Derived-to-base conversion OK
return this;
}
};
今あなたができることはこれです:
base* base_ptr = new A();
IGetSomething *getSmthing = base_ptr->GetSomething();
if (getSmthing != NULL)
{
std::list<something> listOfSmthing = getSmthing->Get();
}
複雑ですが、この方法にはいくつかの利点があります。
具体的な実装クラスではなく、パブリックインターフェイスを返します。
あなたはそれが設計されているもののために継承を使用します。
誤って使用することは困難です。baseはstd::list get()を提供しません。これは、具体的な実装間で一般的な操作ではないためです。
GetSomething()のセマンティクスについて明示的です。これにより、何かのリストを取得するために使用できるインターフェースを返すことができます。
空のstd::listを返すだけではどうでしょうか?
それは可能ですが、悪いデザインです。ペプシにサービスを提供しないことを除けば、コーラとペプシを提供できる自動販売機を持っているようなものです。誤解を招く可能性があり、避けるのが最善です。
ブースト::optional<std :: list <something >>を返すだけではどうでしょうか?(アンドリューによって提案されたように)
これは、場合によってはNULLになることもあれば、そうでないこともあるインターフェースを返すよりも優れた解決策だと思います。そうすれば、それがオプションであり、間違いがないことを明示的に知っているからです。
欠点は、インターフェイス内にブーストを配置することです。これは避けたいと思います(ブーストを使用するのは私次第ですが、インターフェイスのクライアントにブーストの使用を強制する必要はありません)。