C++接口类导致函数调用(Qt)不明确

C++ interface class causes ambiguous function call (Qt)

本文关键字:Qt 不明确 函数调用 接口 C++      更新时间:2023-10-16

这可能是因为我不完全理解C++中的接口是如何工作的,但现在我们开始:

我在QT5中有一个属性类的基本接口。

class IBaseProperty
{
public:
    virtual ~IBaseProperty() {}
    // Returns the property key as a string.
    virtual QString     getKey() = 0;
    // Returns the property value as a raw string.
    virtual QString     getValueRaw() = 0;
    // Sets the property key as a string.
    virtual void        setKey(QString key) = 0;
    // Sets the property value as a raw string.
    virtual void        setValueRaw(QString value) = 0;
};

我还有一个模板化的接口扩展,可以更容易地对处理更特定数据类型的属性进行子类化。

template <class T>
class IProperty : public IBaseProperty
{
public:
    virtual ~IProperty() {}
    // Classifies a property with a Property_t identifier.
    virtual Property_t  getPropertyType() = 0;
    // Returns the property value as the specified type.
    // Bool is true if conversion was successful.
    virtual T           getValue(bool* success) = 0;
    // Sets the property value as the specified type.
    virtual void        setValue(T value) = 0;
    // Returns whether the current value can be converted correctly
    // to the specified type.
    virtual bool        canConvert() = 0;
};

我的基本属性(仅实现IBaseProperty)如下所示:

class BaseProperty : public QObject, public IBaseProperty
{
    Q_OBJECT
public:
    explicit BaseProperty(QObject *parent = 0, QString key = "", QString value = "");
    virtual QString getKey();
    virtual QString getValueRaw();
public slots:
    virtual void setKey(QString key);
    virtual void setValueRaw(QString value);
protected:
    QPair<QString, QString> m_Property; // KV pair this property holds.
};

我将其子类化为字符串属性-显然,基本属性只能返回字符串,但我希望在string/int/float/等之间保持相同的函数格式。属性中的getValue。在这种情况下,GetValue只是简单地调用getValueRaw来返回值。

class StringProperty : public BaseProperty, public IProperty<QString>
{
    Q_OBJECT
public:
    explicit StringProperty(QObject *parent = 0, QString key = "", QString value = "");
    virtual inline Property_t getPropertyType() { return Prop_String; }
    virtual QString     getValue(bool* success);
    virtual bool        canConvert();
public slots:
    virtual void        setValue(QString value);
};

当我实现getValue和setValue:时,会出现歧义

inline QString StringProperty::getValue(bool* success)
{
    *success = canConvert();
    return getValueRaw();      // This line causes the ambiguity.
}

编译器抱怨:

C2385:"getValueRaw"的访问不明确:可能是"getValueRaw"在基"BaseProperty"中,或者可以是基中的"getValueRaw"IBaseProperty"。

我不完全确定在这种情况下该怎么办——我本以为IBaseProperty是一个纯虚拟类意味着函数无论如何都不能从这一点调用,所以只能从它实现的地方(BaseProperty)调用。解决这个问题的正确做法是什么?我不确定应该从哪个基类调用函数。

首先看来,这似乎是经典的钻石问题或钻石继承

String property继承自BasePropertyIProperty,并且它们都具有相同的基类IBaseProperty。这就是为什么会有歧义。

问题是StringProperty包含两个类型为IBaseProperty的基类子对象。您可能只想要一个IBaseProperty,在这种情况下,您需要使用虚拟继承。(将"接口"作为虚拟基类通常是个好主意。)

template <class T>
class IProperty : public virtual IBaseProperty
{ /*...*/ };
class BaseProperty : public virtual IBaseProperty, public QObject
{ Q_OBJECT; /*...*/ };
class StringProperty : public virtual IProperty<QString>, public BaseProperty
{ Q_OBJECT; /*...*/ };

推荐阅读:C++常见问题解答25.8至25.15。