为什么通过派生类使用 :: 运算符引用基类会产生歧义?

3
因此,我想知道为什么以下钻石问题的代码片段无法编译。我知道这个问题通常通过虚拟继承来解决,但我故意没有使用它。这段代码只是为了展示我的问题,即为什么编译器会调用这个模棱两可的函数:所以我在struct Base中声明了两个成员变量,因为这两个子类(在这种情况下是结构体)没有虚拟继承,我将在每个派生结构中引用Base成员。现在我有一个叫做AllDer的另一个结构体,它将遇到两次知道id_和name_的问题。然而,当我明确从Base目标id_和name_时,我不明白为什么这会是模棱两可的,因为直接目标变量是通过::-运算符指定的。
cout << Der1::Base::id_ << Der1::Base::name_ << '\n';

有人能告诉我,为什么编译器在这里出了问题吗?(请原谅可能错误的技术术语) 编译器错误信息显示:“从派生类'AllDer'到基类的转换不明确”。使用MinGW 7.3.0 64位C++和QT Creator。 编辑:由于这个问题似乎被不同的编译器处理方式不同,请查看链接的问题。
#include <string>
#include <iostream>
using std::string; using std::cout;

struct Base
{
    int id_;
    string name_; //target members for readAllDer() in AllDer

    void read()
    {
        cout << id_ << ' ' << name_ << '\n';
    }
};


struct Der1 : public  Base
{
    //Der1 has own reference to id_, name_
    void readDer1()
    {
        cout << id_ << name_ << '\n';
    }
};

struct Der2 : public  Base
{
    //Der2 has own reference to id_, name_
    void readDer2()
    {
        cout << id_ << name_ << '\n';
    }
};

//
struct AllDer : public Der1, public Der2
{

    void readAllDer()
    {
        cout << Der1::Base::id_ << Der1::Base::name_ << '\n'; // Why is this ambiguous? 
    }
};


请在问题中包含精确的错误消息。 - 463035818_is_not_a_number
1
它可以在没有 Base:: 的情况下工作,嗯。 - Yksisarvinen
能在我的电脑上运行,你可以展示一个使用案例吗? - Michael
@Michael OP 也忘了包含错误,但现在我也很好奇你在哪个编译器上没有收到错误。 - 463035818_is_not_a_number
微软CL(Visual Studio 2019)@idclev463035818 - Michael
@Michael 很有趣,gcc和clang都报错了。现在就看OP澄清情况了。 - 463035818_is_not_a_number
3个回答

1

Der1::BaseDer2::Base是同一个类,AllDer从中继承了两次。当你从Der1而不是Base中选择成员时,你的方法可以编译通过:

struct AllDer : public Der1, public Der2
{

    void readAllDer()
    {
        cout << Der1::id_ << Der1::name_ << '\n'; 
    }
};

@Micheal,我不明白你在说什么。OP的代码中没有虚继承,而且我也没有提到虚继承。如果有虚继承,那么AllDer只会包含一个Base子对象,就不会有歧义了。 - 463035818_is_not_a_number
@Michael 不是的,它们都指的是相同类型的 Base。无论如何,我正在考虑删除答案,因为需要澄清问题,但我想我会将其保留。 - 463035818_is_not_a_number
我添加了构造函数, AllDer() : Der1("Michael", 1), Der2("Daniel", 2) {}现在,当我运行以下代码时, cout << Der1::Base::id_ << Der1::Base::name_ << '\n'; // 为什么这是模棱两可的? cout << Der2::Base::id_ << Der2::Base::name_ << '\n'; // 为什么这是模棱两可的?输出我期望的结果,"1Michael\n2Daniel\n" - Michael
我强烈认为这是gcc的一个bug,我会检查一下clang。 - Michael
1
@SörenHepp 因为 Der1::Base 不是一个对象,它是一种类型,并且与 Der2::Base 相同。我开了一个新的问题,因为我有疑问(链接如上)。 - 463035818_is_not_a_number
显示剩余7条评论

0

这是一个经典的钻石问题,即使你通过作用域(::)指定了直接目标变量

在这里,“Der1”已经拥有“id_,name_”的副本,但你仍然试图访问基类的副本,这对于“AllDer”来说是不明确的,因为它是通过Der1和Der2两种方式传递的。

与其这样做:

Der1::Base::id_

试试这个:

Der1::id_ and Der1::name_

希望这可以帮到你


-1

你需要像这样从基类虚拟继承 Der1 和 Der2

struct Der1 : virtual public  Base


struct Der2 : virtual public  Base

在这个链接中说: 虚继承是一种C++技术,确保只有一个基类成员变量的副本被孙子继承


OP非常清楚Base的双重继承,这就是他试图消除_id成员的歧义的原因。 - Yksisarvinen
我不明白为什么这个答案是错误的,但感谢您的评论 @Yksisarvinen。 - MH Alikhani
@Yksisarvinen 如果您能解释一下为什么,我将不胜感激。 - MH Alikhani
3
我不是那个给它踩反对票的人,但 OP 特别不想要虚拟继承(“我知道这个问题通常通过虚拟继承来解决,但我故意没有使用它”)。问题是:“为什么 Der1::Base::_id 是模棱两可的?” - Yksisarvinen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接