你没有别的事可做。您提供的代码正是这样做的。
当你得到一个指向基类的指针时,由于方法是在基类中声明的,并且是虚拟的,实际的实现将在类的虚函数表中查找并适当地调用。
所以
base* base_ptr = new A();
base_ptr->get();
将调用 A::get()。你不应该从实现中返回 null (你不能,因为 null 无论如何都不能转换为 std::list< something >)。由于基类方法被声明为纯虚拟,因此您必须在 A/B 中提供实现。
编辑:
你不能只让 A 返回一个 std::list< something > 而不是 B 因为 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 是一个纯接口(它没有成员变量或非纯方法)。
编辑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();
}
它很复杂,但这种方法有几个优点:
这是可能的,但糟糕的设计,就像拥有一台可以提供可口可乐和百事可乐的自动售货机,但它从不供应百事可乐;它具有误导性,最好避免。
只返回一个 boost::optional< std::list< something >> 怎么样?(由安德鲁建议)
我认为这是一个更好的解决方案,比返回和有时可能为 NULL 有时不是的接口更好,因为这样您就明确知道它是可选的,并且不会有任何错误。
缺点是它将 boost 放在你的界面中,我更愿意避免这种情况(使用 boost 取决于我,但界面的客户端不应该被迫使用 boost)。