[英]Multiple inheritance, virtual methods collision and pointers from base classes
我有一个结果,我没想到多重继承, virtual
方法和指向基类的指针。
使用d.getStr()
,当d
是derived
实例时,将base_2
版本,正如我所期望的那样。
使用p->getStr()
,当p
是指向derived
实例的指针(或指向指向derived
实例的base_2
指针)时,会调用base_2
版本,正如我所期望的那样。
但随着p->getStr()
当p
是一个指向base_1
指向derived
例如, base_1
版本被称为,我确信会被称为base_2
版本(感谢using
,事实上, getStr()
是virtual
方法)。
以下是一个简单的例子:
#include <iostream>
struct base_1
{
virtual std::string getStr () const
{ return "string from base 1"; }
};
struct base_2
{
virtual std::string getStr () const
{ return "string from base 2"; }
};
struct derived : public base_1, public base_2
{
using base_2::getStr;
};
int main ()
{
derived d;
derived * dp = &d;
base_1 * bp1 = &d;
base_2 * bp2 = &d;
std::cout << "from derived: " << d.getStr() << std::endl;
std::cout << "from derived pointer: " << dp->getStr() << std::endl;
std::cout << "from base_1 pointer: " << bp1->getStr() << std::endl;
std::cout << "from base_2 pointer: " << bp2->getStr() << std::endl;
}
输出如下
from derived: string from base 2
from derived pointer: string from base 2
from base_1 pointer: string from base 1
from base_2 pointer: string from base 2
我知道,为了强制调用base_2
版本,我可以添加derived
以下方法
std::string getStr () const
{ return base_2::getStr(); }
但我的问题是:
1)为什么指向base_1
(指向派生实例)的指针忽略using
指令并调用getStr()
的base_1
版本?
2)有没有办法强加给base_2
的版本getStr()
当derived
实例使用由base_1
指针,而无需再定义getStr()
---编辑---
谢谢你的回答。
我知道你在描述正在发生的事情,但我怀疑的是:语言(标准)是否描述了这方面的内容? 或者它是一个未定义的部分?
我的意思是:如果我删除using
指令,我从d.getStr()
和dp->getStr()
得到编译错误( error: request for member getStr is ambiguous
dp->getStr()
,因为编译器不知道哪个版本选择getStr()
但是getStr()
是virtual
方法。 所以(我确信)一个基指针应该使用它们的派生版本。 但我们有几种相互碰撞的方法。
从语言(标准)的角度来看, base_1
(或base_2
)是被授权(或有义务)选择忽略另一个的碰撞方法的两个版本之一的指针?
也许我错了,但在我看来,通过这种方式, virtual
方法作为非virtual
方法进行管理。
您希望以下列方式using
关键字时:
struct derived : public base_1, public base_2
{
using base_2::getStr;
};
这与以下相同:
struct derived : public base_1, public base_2
{
void getStr()
{
base_2::getStr();
}
};
在这种情况下,您期望的行为 - 当p是指向base_1
的指针时,调用p->getStr()
- 实际上最终会调用base_2::getStr()
。 derived
覆盖了base_1
的getStr()
,因此通过普通指针调用base_1
的getStr
()会导致derived
的getStr
()被调用,从而调用base_2
getStr()
方法。
然而,这不是发生的事情。 using
关键字不是以这种方式转发方法调用的别名。 using
关键字不会在derived
'd类中创建方法,因此类继承不受影响,并且derived_1
的getStr()
不会在subclsas中被覆盖。 这就是为什么调用derived_1
的getStr()
不会最终调用derived_2
的getStr()
。
这是因为派生类必须为getStr()
提供2个vtable条目,每个基类一个,因此它可以正确解析base_1::getStr()
和base_2::getStr()
。 using
指令不创建derived::getStr()
vtable条目或替换基类类,它只选择将使用哪个基类条目。 当通过指向base_1
的指针时,编译器只从derived
和base_1
“看到”虚函数的vtable条目,因此它将getStr()
解析为base_1::getStr()
。 您在derived
中添加显式getStr()
解决方案可能是最干净的解决方案,但为了清楚起见,建议将其设置为虚拟以匹配基类。
1)似乎你的代码正在完成它应该做的事情。 您指向base_1,因此您从base_1(或其任何基类)获取函数。 该对象由base_1和base_2组成,此时未知,因为您指向基类,而不是派生类。
2)不,这根本不可能。 您必须确实在derived
重载getStr()。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.