我有以下多重继承结构,其中包含一个空基和两个空的派生类(两者都代表不同的功能,但这都是遗漏的)。我有另一个类需要这两个功能,因此从两个接口继承。下面的设置使用visual studio 2015进行编译,但不能使用gcc 6或clang3.8编译。 gcc抱怨Base是一个模糊的DerivedC基类
gcc错误:
error: ‘Base’ is an ambiguous base of ‘DerivedC’
std::cout << "derivedC.typeId()" << dc.typeId() << std::endl;
Clang错误:
ambiguous conversion from derived class 'DerivedC' to base class 'const Base':
class DerivedC -> class DerivedA -> class Base
class DerivedC -> class DerivedB -> class Base
std::cout << "derivedC.typeId()" << dc.typeId() << std::endl;
在使用这些类时,我需要将(指针)Base模型转换为(指向)DerivedC模型的指针。如果我将虚拟多重继承,我需要做一个我想避免的dynamic_cast。有什么方法可以让gcc和clang了解我想采取的钻石方向?在我看来,“使用DerivedA :: typeId”处理这个问题(就像它在VS中一样(如果缺少使用它会发出抱怨))。有趣的是,当你将鼠标悬停在代码上时,VS确实“表示一个模糊的基本错误”问题。但是,它会编译它并返回所需的值。
任何帮助非常感谢。 迈克
代码:
#include <iostream>
class Base
{
public:
int typeId() const {
return doTypeId();
}
private:
virtual int doTypeId() const = 0;
};
class DerivedA : public Base
{
public:
private:
virtual int doTypeId() const override { return 1; }
};
class DerivedB : public Base
{
public:
private:
virtual int doTypeId() const override { return 2; }
};
class DerivedC : public DerivedA, public DerivedB
{
public:
using DerivedA::typeId;
private:
virtual int doTypeId() const override { return 3; }
};
int main(void) {
auto da = DerivedA();
std::cout << "DerivedA.typeId() = " << da.typeId() << std::endl;
auto db = DerivedB();
std::cout << "DerivedB.typeId() = " << db.typeId() << std::endl;
auto dc = DerivedC();
std::cout << "derivedC.typeId() = " << dc.typeId() << std::endl;
}
答案 0 :(得分:0)
因为您没有使用虚拟继承,所以您没有钻石。您有两个Base
实例-------- -------- | Base | | Base | | #1 | | #2 | -------- -------- V V ------------ ------------ | DerivedA | | DerivedB | ------------ ------------ V V ------------ | DerivedC | ------------
这意味着DerivedC的v表有两个用于虚方法doTypeId()的槽。派生C中的doTypeId()定义覆盖了哪一个? [这不是这里的实际问题,但是如果你解决这个问题就必须应付这个问题]
'using'语句无法解决问题。它将方法的声明从DerivedA类提升到using
出现的上下文中。如果DerivedB中方法的签名不同,它将被using
隐藏,但由于它是相同的,它仍然可用。
该名称未在DerivedC中声明,但编译器不会跟踪名称的来源。因此,电话仍然含糊不清。为了调用Base
中声明的成员,它必须知道要传递的内容为this
指针并且它无法分辨。
底线:使用虚拟继承。