多重继承,虚拟方法冲突和来自基类的指针 [英] Multiple inheritance, virtual methods collision and pointers from base classes

查看:153
本文介绍了多重继承,虚拟方法冲突和来自基类的指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个意外的结果,那就是多重继承,virtual方法和基类指针.

I have a result that I didn't expect from multiple inheritance, virtual methods and pointers to base classes.

对于d.getStr(),当dderived实例时,将调用base_2版本,正如我期望的那样.

With d.getStr(), when d is a derived instance, the base_2 version is called, as I expected.

对于p->getStr(),当p是指向derived实例的指针(或指向base_2的指针指向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是指向base_1的指针,该指针指向derived实例时,会调用base_1版本,并且我确信它将被称为base_2版本(谢谢) usinggetStr()virtual方法的事实).

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).

以下是一个简单的示例:

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;
}

输出如下

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中添加以下方法

I know that, to impose the call of base_2 version, I can add in derived the following method

std::string getStr () const
 { return base_2::getStr(); }

但是我的问题是:

1)为什么指向base_1的指针(指向派生实例)忽略using指令并调用getStr()base_1版本?

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()?

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

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()?

---编辑---

感谢您的回答.

我了解您正在描述正在发生的事情,但我的疑问是:语言(标准)是否描述了这方面?还是未定义的部分?

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?

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

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.

但是getStr()virtual方法.因此(我坚信)基本指针应使用它们的派生版本.但是我们有两种碰撞方法.

But getStr() are virtual methods. So (I was convinced that) a base pointer should use the derived version of they. But we have a couple of colliding methods.

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

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?

也许我错了,但在我看来,以这种方式,virtual方法被作为非virtual方法管理.

Maybe I'm wrong but seems to me that, in this way, the virtual methods are managed as non virtual methods.

推荐答案

您期望通过以下方式使用using关键字:

You are expecting that when you using the using keyword in the following manner:

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->getStr()(当p是指向base_1的指针时)的确会最终调用base_2::getStr(). derived覆盖base_1getStr(),因此通过普通指针调用base_1getStr()会导致调用derivedgetStr(),从而调用 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(). 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.

但是,这不会发生. using关键字不是以这种方式转发方法调用的别名. using关键字不会在derived的类中创建方法,因此类继承不会受到影响,并且derived_1getStr()不会在子clsas中被覆盖.这就是为什么调用derived_1getStr()不会结束调用derived_2getStr()的原因.

However, this is not what happens. The using keyword is not an alias for forwarding a method call in this manner. 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. And that's why invoking derived_1's getStr() does not wind up invoking derived_2's getStr().

这篇关于多重继承,虚拟方法冲突和来自基类的指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆