gpt4 book ai didi

c++ - 多重继承引起的C++拷贝构造函数调用不明确

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:34:24 26 4
gpt4 key购买 nike

我在执行某项任务时遇到了问题,这是一个练习,而不是一个真正的程序。任务是定义结构 D 的复制构造函数,其行为方式与编译器生成的复制构造函数完全相同。

class Ob{
};

struct A {
Ob a;
};

struct B : A {
Ob b;
};

struct C : A, B {
Ob c;
};

struct D : C, A {
Ob d;
};

如您所见,结构 A 在结构 D 中间接派生了几次,这导致了复制构造函数定义中的歧义,如下所示:

D(const D& _d) : C(_d), A(_d), d(_d.d) {}

我的问题是如何正确定义复制构造函数?没有上述定义的代码编译通过,所以看起来应该是可以的。

MinGW 4.8.1 错误信息:

zad3.cpp:12:8: warning: direct base 'A' inaccessible in 'C' due to ambiguity     [enabled by default]
struct C : A, B {
^
zad3.cpp:16:8: warning: direct base 'A' inaccessible in 'D' due to ambiguity [enabled by default]
struct D : C, A {
^
zad3.cpp: In copy constructor 'D::D(const D&)':
zad3.cpp:17:38: error: 'A' is an ambiguous base of 'D'
D(const D& _d) : C(_d), A(_d), d(_d.d) {}
^

重要提示:这是不是重复问题“Inaccessible direct base caused by multiple inheritance”,这是关于具有不同访问说明符的公共(public)基类,最终是由转换问题引起的。这里是关于消除以相同的可见性多次继承的公共(public)基类的必需初始化器的歧义。

最佳答案

注意:答案经过根本性编辑!

问题分析:

您正在使用 multiple inheritance with a diamond problem .

更具体地说,您的结构 D 继承相同的基类 A 三次:一次直接(struct D: C,A)和两次间接(通过 C 的继承)。由于基类不是虚拟的,因此 D 有 3 个不同的 A 子对象。C++11 标准部分 10.1/4-5 称其为格子:

inheritance diagram

通常,您随后会通过显式限定来消除每个 A 的成员的歧义,告诉编译器您指的是 3 个 A 子对象中的哪一个。 C++11 第 10.1/5 节对此进行了解释。成员的语法应该是 A::a, C::aB::aD< 范围内,如果您在外面,每个最终都以 D:: 开头。

不幸的是,C++11 section 10.2/5-6 中的成员名称查找逻辑确保直接 A 基总是使其他间接 A 基础不明确,尽管有明确的限定(甚至 using 语句)。

最终解决方案:

由于问题是由直接基类引起的,而且事实上没有办法区分这个与其他类的歧义,唯一真正有效的解决方案是使用一个空的中间类来强制使用不同的名称:

struct Ob{ int v; };    // v aded here to allow verification of copy of all members
struct A { Ob a; };
struct B : A { Ob b; };
struct A1 : A {}; // intermediary class just for diambiguation of A in C
struct C : A1, B { Ob c; }; // use A1 instead of A
struct A2 : A { }; // intermediary class just for diambiguation of A in D
struct D : C, A2 { // use A2 instead of A
Ob d;
D() { }
D(const D& _d) : C(_d), A2(_d), d(_d.d) { }
};

int main(int ac, char**av)
{
cout << "Multiple inheritance\n";
D x;
x.A2::a.v = 1; // without A2:: it's ambiguous
x.A1::a.v = 2; // without A1:: it's ambiguous
x.B::a.v = 3;
x.b.v = 4;
x.d.v = 5;

D y = x;
cout << "The moment of truth: if not 1 2 3 4 5, there's a problem!\n";
cout << y.A2::a.v << endl;
cout << y.A1::a.v << endl;
cout << y.B::a.v << endl;
cout << y.b.v << endl;
cout << y.d.v << endl;
}

此代码编译并使用 MSVC2013、clang 3.4.1 和 gcc 4.9。


其他(非)解决方案:

我之前的回答仅基于明确的限定条件。尽管有很多批评,但我真的在 MSVC2013 上编译和测试成功了!然而,它们是一件奇怪的事情:在编辑器中,intelisence 突出了一个歧义,但编译运行良好,没有任何错误。我最初认为这是一个智能错误,但现在意识到这是一个编译器不合规性(错误?)

提示D(const D& other) : C(other), A((const B)other), d(other.d)的答案编译通过,但没有通过测试。为什么 ?因为 A((const B)other) 会将 other 理解为 B。因此 D 中的 A 将使用间接继承自 BA 的值进行初始化(所以另一个A)。这是一个极其严重的错误,我花了一段时间才注意到。

当然你可以使用虚基类。那么D中就只有一个A子对象了,解决了很多问题。但是我不知道你在设计什么,有些设计需要一个格子而不是一个虚拟的菱形。

如果你能负担得起两步复制(第 1 步:基的默认初始化;第 2 步:复制基上的目标值),当然有一些方法使用无歧义的成员函数返回正确基的引用。但这可能比上面介绍的简单解决方案更棘手且更容易出错。

关于c++ - 多重继承引起的C++拷贝构造函数调用不明确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26832200/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com