修复C++多继承模糊调用

Fixing C++ Multiple Inheritance Ambiguous Call

本文关键字:模糊 调用 继承 C++ 修复      更新时间:2023-10-16

我有三个类的结构如下:

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

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

更新
在阅读了您的评论后,我最初的想法是,也许我可以通过模板化AddressType来描述AddressTypeCharacterKeywordAddressTypeMeasurementKeyword。并在更新后的代码中使用它或者我可以指定我想要的成员的名称空间。既然模板化的方式还没有被提及作为答案,那么这是一个糟糕的解决方案吗?我应该只指定我想要的成员的名称空间吗?

template <class T>
class AddressType : public T
{
    private:
        float address;
        float addresExt;
};
int main()
{
    AddressType<MeasurementKeyword> *a = new AddressType<MeasurementKeyword>();
    a->GetValue();
    return 0;
}

这是因为菱形继承模式,为了解决错误,您可以指定想要成员的特定命名空间。

paddressType->MeasurementKeyword::GetValue()

paddressType->CharacterKeyword::GetValue()  

  1. 基本上,您的AddressType类可以访问它继承的两个类中的GetValue成员,并且不能选择其中一个(调用不明确)
  2. 作用域解析运算符(::)有助于指定实际需要的运算符
  3. 你还没有说你真正想要这个代码做什么,所以我只想说,通常复杂的继承模式不利于创建可读的代码,重新思考你真正想要的是什么

这样定义AddressType:

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

通常,当你遇到致命的死亡钻石时,这表明你应该重新思考你的设计。但是,如果您绝对无法避免这种情况,C++将以虚拟继承的形式提供一个解决方案。虚拟继承解决了一些"钻石模糊性",但它也很笨拙。例如,您必须在派生类的构造函数中显式调用父级的非默认构造函数。

再说一次,最好的方法是从一开始就避开钻石。我已经用C++编程很多年了,到目前为止,我的代码中从未遇到过这个问题。