【问题标题】:Fixing C++ Multiple Inheritance Ambiguous Call修复 C++ 多重继承歧义调用
【发布时间】:2013-08-10 11:23:13
【问题描述】:

我有三个这样的类:

#include <iostream>
using namespace std;

class Keyword
{
    public:
        virtual float GetValue() = 0;
};

class CharacterKeyword : public Keyword
{
    public:
        virtual float GetValue(){return _value;}
    private:
        float _value;
};

class MeasurementKeyword : public Keyword
{
    public:
        virtual float GetValue(){return _value;}
    private:
        float _value;
};

class AddressType : public CharacterKeyword, public MeasurementKeyword
{

    private:
        float address;
        float addresExt;
};

int main()
{
    AddressType *a = new AddressType();
    a->GetValue();
    return 0;
}

我收到以下信息:

In function ‘int main()’:
error: request for member ‘GetValue’ is ambiguous
error: candidates are: virtual float Keyword::GetValue()
error: virtual float MeasurementKeyword::GetValue()
error: virtual float CharacterKeyword::GetValue()

我对多重继承做了一些阅读,我知道它有很多陷阱——这就是其中之一。我需要我的类结构是这样的,所以我想知道是否有一种方法可以使用模板来解决这个问题?

更新
在阅读了您的 cmets 之后,我最初的想法是,也许我可以通过模板化 AddressTypeAddressType(即 CharacterKeyword)和 AddressType(即 MeasurementKeyword)之间划定界限。并在更新的代码中使用它。 我可以指定我想要的成员的命名空间。由于尚未提及模板化方式作为答案,这是一个不好的解决方法吗?我应该只指定我想要的成员的命名空间吗?

template <class T>
class AddressType : public T
{

    private:
        float address;
        float addresExt;
};

int main()
{
    AddressType<MeasurementKeyword> *a = new AddressType<MeasurementKeyword>();
    a->GetValue();
    return 0;
}

【问题讨论】:

  • 取决于你想如何解决这个问题。你想在这里发生什么?
  • @KarthikT 这就是我给他两种方式的原因;)
  • @aaronman 是的,没有错您的解决方案,但不确定他想用模板完成什么..
  • @KarthikT 实际上我去掉了标题中的模板,因为它似乎与它们无关
  • larry 正如您在 cmets 中看到的那样,模板在这里确实不相关,所以我删除了它们,我的答案或底部的答案是您解决歧义的方法

标签: c++ virtual-inheritance diamond-problem


【解决方案1】:

这是因为diamond inheritance pattern,要解决该错误,您可以指定您希望成员喜欢的特定命名空间。

paddressType->MeasurementKeyword::GetValue()

paddressType->CharacterKeyword::GetValue()  

  1. 基本上,您的AddressType 类可以访问它所继承的两个类中的GetValue 成员,并且不能选择一个(调用不明确)。
  2. scope resolution operator (:: ) 有助于指定您真正想要的。
  3. 你还没有说你真正想要这段代码做什么,所以我只想说通常复杂的继承模式不利于创建可读的代码,重新考虑你真正想要的。

【讨论】:

    【解决方案2】:

    像这样定义地址类型:

    class AddressType : public CharacterKeyword, public MeasurementKeyword
    {
    public:
        using MeasurementKeyword::GetValue;
    private:
        float address;
        float addresExt;
    };
    

    【讨论】:

      【解决方案3】:

      通常,当您遇到deadly diamond of death 时,这表明您应该重新考虑您的设计。但是,如果您绝对无法避免这种情况,C++ 以virtual inheritance 的形式提供了解决方案。虚拟继承解决了一些“钻石歧义”,但它也很笨拙。例如,您必须在派生类的构造函数中显式调用父类的非默认构造函数。

      再一次,最好的方法是首先避开钻石。我用 C++ 编程很多年了,到目前为止,我的代码中从来没有遇到过这个问题。

      【讨论】:

      • "你必须在派生类的构造函数中显式调用父类的构造函数。"您的意思是虚拟基类在最派生类中初始化?如果虚拟基类中有默认的ctors,则不需要显式调用它们。
      • 虚拟没有解决这个问题,调用还是有歧义,其余的我同意
      • @DyP 是的。我的意思是你需要提到父母的班级。
      • 我有一个有趣的案例,A 定义了一个纯虚函数,B 实现了它,但C 没有,我希望D 使用B 的实现.解决方案是将C 设为公共虚拟A,感谢您的回答!
      猜你喜欢
      • 1970-01-01
      • 2011-10-14
      • 1970-01-01
      • 1970-01-01
      • 2013-10-17
      • 2016-05-07
      • 2012-05-08
      • 2018-05-23
      • 1970-01-01
      相关资源
      最近更新 更多