Nic*_*ick 3 c++ polymorphism inheritance virtual-functions
假设我在base接口中有一个纯虚方法,它返回给我一个列表something:
class base
{
public:
virtual std::list<something> get() = 0;
};
Run Code Online (Sandbox Code Playgroud)
假设我有两个继承base该类的类:
class A : public base
{
public:
std::list<something> get();
};
class B : public base
{
public:
std::list<something> get();
};
Run Code Online (Sandbox Code Playgroud)
我希望只有A类可以返回一个list<something>,但我还需要有可能使用base指针获取列表,例如:
base* base_ptr = new A();
base_ptr->get();
Run Code Online (Sandbox Code Playgroud)
我该怎么办?
我是否要返回指向此列表的指针?参考?
我是否要从类的方法返回空指针B?或者,当我尝试使用B对象获取列表时,是否要抛出异常?或者我要改变base类方法get,使它不纯,并在base课堂上做这个工作?
我还有别的事吗?
你别无他法.您提供的代码正是如此.
当您获得指向基类的指针时,由于该方法是在基类中声明的,并且是虚拟的,因此将在类虚函数表中查找实际实现并进行适当调用.
所以
base* base_ptr = new A();
base_ptr->get();
Run Code Online (Sandbox Code Playgroud)
将调用A :: get().你不应该从实现中返回null(你不能,因为null无法转换为std :: list <something>).您必须在A/B中提供实现,因为基类方法被声明为纯虚拟.
编辑:
你不能只返回一个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
{
};
Run Code Online (Sandbox Code Playgroud)
在这种情况下,多重继承是可以的,因为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;
}
};
Run Code Online (Sandbox Code Playgroud)
现在你可以做的是:
base* base_ptr = new A();
IGetSomething *getSmthing = base_ptr->GetSomething();
if (getSmthing != NULL)
{
std::list<something> listOfSmthing = getSmthing->Get();
}
Run Code Online (Sandbox Code Playgroud)
这是令人费解的,但这种方法有几个优点:
您明确了GetSomething()的语义:它允许您返回可用于检索某些内容列表的接口.
那么只返回一个空的std :: list呢?
这是可能的,但糟糕的设计,就像拥有可以给可口可乐和百事可乐的自动售货机,除了它从未服务百事可乐; 这是误导,最好避免.
那么只返回一个boost :: optional <std :: list <something >>?(正如Andrew所说)
我认为这是一个更好的解决方案,比返回和接口更好,有时可能是NULL,有时不是,因为那时你明确地知道它是可选的,并且没有错误.
缺点是它会在你的界面中加入,我更愿意避免(这取决于我使用boost,但接口的客户端不应该被迫使用boost).