多重继承,虚方法冲突和基类

时间:2016-06-19 18:08:02

标签: c++ polymorphism language-lawyer multiple-inheritance

我有一个结果,我没想到多重继承,virtual方法和指向基类的指针。

使用d.getStr(),当dderived个实例时,会调用base_2版本,正如我预期的那样。

使用p->getStr(),当p是指向derived实例的指针(或指向base_2实例的derived指针)时,{正如我所料,调用{1}}版本。

但是对于base_2,当p->getStr()是指向p实例的base_1的指针时,derived版本被调用,我确信将被称为base_1版本(感谢base_2以及usinggetStr()方法的事实)。

以下是一个简单的例子:

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

但我的问题是:

1)为什么指向std::string getStr () const { return base_2::getStr(); } (指向派生实例)的指针忽略base_1指令并调用using base_1版本?

2)当getStr()指针使用base_2实例而没有重新定义getStr()时,是否有办法强加derived base_1版本getStr()

---编辑---

感谢您的回答。

我知道你在描述正在发生的事情,但我怀疑的是:语言(标准)是否描述了这方面的内容?或者它是一个未定义的部分?

我的意思是:如果我删除using指令,我会从error: request for member getStr is ambiguousd.getStr()收到编译错误(dp->getStr()),因为编译器没有知道要选择哪个版本的getStr()

getStr()virtual方法。所以(我确信)一个基指针应该使用它们的派生版本。但我们有几种相互碰撞的方法。

从语言(标准)的角度来看,base_1(或base_2)是指定(或有义务)选择碰撞方法的两个版本中的一个而忽略另一个的指针吗?

也许我错了,但在我看来,virtual方法以非virtual方法进行管理。

3 个答案:

答案 0 :(得分:4)

您希望以下列方式使用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是指向p->getStr()的指针时调用base_1 - 实际上最终会调用base_2::getStr()derived会覆盖base_1&#39; getStr(),因此通过普通指针调用base_1&#39; getStr()会导致{ {1}} derived()被调用,调用getStr base_2方法。

但是,这不是发生的事情。 getStr()关键字不是以这种方式转发方法调用的别名。 using关键字不会在using&lt; d;类中创建方法,因此类继承不受影响,derived&#39; s derived_1不会在subclsas中获得覆盖。这就是为什么调用getStr()&#39; derived_1无法调用getStr() derived_2

答案 1 :(得分:2)

这是因为派生类必须为$ which python /Users/PatrickT/miniconda3/bin/python 提供2个vtable条目,每个基类一个,因此它可以正确解析getStr()base_1::getStr()base_2::getStr()指令不创建using vtable条目或替换基类条目,它只选择将使用哪个基类条目。当通过指向derived::getStr()的指针时,编译器只会&#34;看到&#34;来自base_1derived的虚拟函数的vtable条目,因此它将base_1解析为getStr()。您在base_1::getStr()中添加显式getStr()的解决方案可能是最干净的,但为了清晰起见,最好使其与基类匹配。

答案 2 :(得分:0)

1)似乎你的代码完全按照它应该做的去做。您指向base_1,因此您从base_1(或其任何基类)获取函数。该对象由base_1和base_2组成,此时未知,因为您指的是基类,而不是派生类。

2)不,这根本不可能。你必须在derived中重载getStr()。