[英]Multiple inheritance, virtual methods collision and pointers from base classes
I have a result that I didn't expect from multiple inheritance, virtual
methods and pointers to base classes. 我有一个结果,我没想到多重继承,
virtual
方法和指向基类的指针。
With d.getStr()
, when d
is a derived
instance, the base_2
version is called, as I expected. 使用
d.getStr()
,当d
是derived
实例时,将base_2
版本,正如我所期望的那样。
With p->getStr()
, when p
is a pointer to a derived
instance (or a pointer to base_2
pointing to a derived
instance), the base_2
version is called, as I expected. 使用
p->getStr()
,当p
是指向derived
实例的指针(或指向指向derived
实例的base_2
指针)时,会调用base_2
版本,正如我所期望的那样。
But with p->getStr()
, when p
is a pointer to a base_1
pointing to a derived
instance, the base_1
version is called and I was convinced would be called the base_2
version (thanks the using
and the fact that getStr()
are virtual
methods). 但随着
p->getStr()
当p
是一个指向base_1
指向derived
例如, base_1
版本被称为,我确信会被称为base_2
版本(感谢using
,事实上, getStr()
是virtual
方法)。
The following is a simple example: 以下是一个简单的例子:
#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;
}
The output is the following 输出如下
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
I know that, to impose the call of base_2
version, I can add in derived
the following method 我知道,为了强制调用
base_2
版本,我可以添加derived
以下方法
std::string getStr () const
{ return base_2::getStr(); }
but my questions are: 但我的问题是:
1) Why does the pointer to base_1
(pointing to a derived instance) ignore the using
directive and call the base_1
version of getStr()
? 1)为什么指向
base_1
(指向派生实例)的指针忽略using
指令并调用getStr()
的base_1
版本?
2) Is there a way to impose the base_2
version of getStr()
, when derived
instance is used by a base_1
pointer, without redefining getStr()
? 2)有没有办法强加给
base_2
的版本getStr()
当derived
实例使用由base_1
指针,而无需再定义getStr()
--- EDIT --- ---编辑---
Thanks for the answers. 谢谢你的回答。
I understand that you are describing what's happening but my doubt is: does the language (the standard) describe this aspect? 我知道你在描述正在发生的事情,但我怀疑的是:语言(标准)是否描述了这方面的内容? Or is it an undefined part?
或者它是一个未定义的部分?
I mean: if I remove the using
directive, I get a compilation error ( error: request for member getStr is ambiguous
), from d.getStr()
and from dp->getStr()
, because the compiler doesn't know which version of getStr()
to chose. 我的意思是:如果我删除
using
指令,我从d.getStr()
和dp->getStr()
得到编译错误( error: request for member getStr is ambiguous
dp->getStr()
,因为编译器不知道哪个版本选择getStr()
But getStr()
are virtual
methods. 但是
getStr()
是virtual
方法。 So (I was convinced that) a base pointer should use the derived version of they. 所以(我确信)一个基指针应该使用它们的派生版本。 But we have a couple of colliding methods.
但我们有几种相互碰撞的方法。
From the language (standard) point of view, a base_1
(or base_2
) is the pointer authorized (or obligated) to choose one of the two versions of the colliding methods ignoring the other? 从语言(标准)的角度来看,
base_1
(或base_2
)是被授权(或有义务)选择忽略另一个的碰撞方法的两个版本之一的指针?
Maybe I'm wrong but seems to me that, in this way, the virtual
methods are managed as non virtual
methods. 也许我错了,但在我看来,通过这种方式,
virtual
方法作为非virtual
方法进行管理。
You are expecting that when you using the using
keyword in the following manner: 您希望以下列方式
using
关键字时:
struct derived : public base_1, public base_2
{
using base_2::getStr;
};
That this is the same as: 这与以下相同:
struct derived : public base_1, public base_2
{
void getStr()
{
base_2::getStr();
}
};
In this case, the behavior you are expecting -- invoking p->getStr()
, when p is a pointer to a base_1
-- would, indeed, end up invoking base_2::getStr()
. 在这种情况下,您期望的行为 - 当p是指向
base_1
的指针时,调用p->getStr()
- 实际上最终会调用base_2::getStr()
。 derived
overrides base_1
's getStr()
, so invoking base_1
's getStr
(), through an ordinary pointer, results in derived
's getStr
() getting invoked, which invokes base_2
getStr()
method. derived
覆盖了base_1
的getStr()
,因此通过普通指针调用base_1
的getStr
()会导致derived
的getStr
()被调用,从而调用base_2
getStr()
方法。
However, this is not what happens. 然而,这不是发生的事情。 The
using
keyword is not an alias for forwarding a method call in this manner. using
关键字不是以这种方式转发方法调用的别名。 The using
keyword does not create a method in derived
'd class, so class inheritance is not affected, and derived_1
's getStr()
does not get overriden in the subclsas. using
关键字不会在derived
'd类中创建方法,因此类继承不受影响,并且derived_1
的getStr()
不会在subclsas中被覆盖。 And that's why invoking derived_1
's getStr()
does not wind up invoking derived_2
's getStr()
. 这就是为什么调用
derived_1
的getStr()
不会最终调用derived_2
的getStr()
。
That happens because the derived class has to have 2 vtable entries for getStr()
, one for each base class, so it can correctly resolve both base_1::getStr()
and base_2::getStr()
. 这是因为派生类必须为
getStr()
提供2个vtable条目,每个基类一个,因此它可以正确解析base_1::getStr()
和base_2::getStr()
。 The using
directive doesn't create a derived::getStr()
vtable entry or replace the base-class ones, it just selects which base-class entry will be used. using
指令不创建derived::getStr()
vtable条目或替换基类类,它只选择将使用哪个基类条目。 When going through a pointer to base_1
, the compiler only "sees" the vtable entries for virtual functions from derived
and base_1
so it resolves getStr()
to base_1::getStr()
. 当通过指向
base_1
的指针时,编译器只从derived
和base_1
“看到”虚函数的vtable条目,因此它将getStr()
解析为base_1::getStr()
。 Your solution of adding an explicit getStr()
in derived
is probably the cleanest one, although it might be advisable to make it virtual to match the base classes for clarity. 您在
derived
中添加显式getStr()
解决方案可能是最干净的解决方案,但为了清楚起见,建议将其设置为虚拟以匹配基类。
1) Seems like your code is doing exactly what it's supposed to do. 1)似乎你的代码正在完成它应该做的事情。 You point to base_1, so you get functions from base_1 (or any of its base classes).
您指向base_1,因此您从base_1(或其任何基类)获取函数。 That the object is made up of both base_1 and base_2 is unknown at that point, because you are point to a base class, not a derived class.
该对象由base_1和base_2组成,此时未知,因为您指向基类,而不是派生类。
2) No, that is simply impossible. 2)不,这根本不可能。 You must indeed overload getStr() in
derived
. 您必须确实在
derived
重载getStr()。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.