C++ 在C++;由多重继承引起的
我对某项任务有问题,这是一种锻炼,不是真正的计划。任务是定义结构D的复制构造函数,其行为方式与编译器生成的复制构造函数完全相同C++ 在C++;由多重继承引起的,c++,multiple-inheritance,copy-constructor,ambiguity,ambiguous,C++,Multiple Inheritance,Copy Constructor,Ambiguity,Ambiguous,我对某项任务有问题,这是一种锻炼,不是真正的计划。任务是定义结构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(
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) {}
^
重要备注:这不是“多重继承导致无法访问的直接基”问题的重复,该问题涉及具有不同访问说明符的公共基类,最终是由转换问题引起的。在这里,它是关于消除一个公共基所需的初始值设定项的歧义,该公共基以相同的可见性多次继承 编译器生成的复制构造函数将调用GrandFather基类的默认构造函数。这可能不是你想要的。 要使一个干净的设计只调用复制构造函数,您应该实现每个类的复制构造函数,并确保根据需要调用它们。在当前的层次结构示例中,不能直接从D转换为A
A(const A& other), a(other.a) {
}
//...
B(const B& other) : A(other), b(other.b) {
}
//...
C(const C& other) : B(other), A((const B)other), c(other.c) {
}
//...
D(const D& other) : C(other), A((const B)other), d(other.d) {
}
进一步编辑:
但首先,为了避免练习中的许多模糊问题,你们应该使用
在您的例子中,从C到A的路径不明确:C->A或C->B->A
要将A声明为层次结构中的公共祖先,可以将从B或C到A的继承声明为虚拟继承。
从D到A还有一个不明确的路径:D->A,或(D->C->A,或D->C->B−>A) 。因此,您还将从D到A的继承声明为虚拟继承
struct B : public virtual A { ... }
struct C : public virtual A, public B { ... }
struct D : public C, public virtual A { ... }
现在在您的层次结构中只有一个共享实例。然后,您可以根据需要编写D copy构造函数:
D(const D& other) : C(other), A(other), d(other.d)
成员D::A::A将与D::C::A::A或D::C::B::A::A相同。注意:答案已编辑强>
问题分析:
您正在使用
更具体地说,您的结构D
三次继承相同的基A
类:一次直接继承(struct D:C,A
),两次间接继承(通过继承C)。由于基类不是虚拟的,因此D++11有3个不同的A子对象。标准第10.1/4-5节称之为A晶格:
通常,您会使用明确的限定条件消除每个A
成员的歧义,告诉编译器您引用的是3个子对象中的哪一个。C++11第10.1/5节对此进行了解释。成员的语法应该是D
范围内的A::A
、C::A
和B::A
,如果您不在D::
范围内,则每个成员的前面都应该有D:
不幸的是,C++11第10.2/5-6节中的成员名称查找逻辑确保直接A
基始终会使其他间接A
基模糊不清,尽管有明确的限定(甚至使用语句)
最终解决方案:
由于问题是由直接基类引起的,并且没有办法将这个基类与其他基类区分开来,因此唯一有效的解决方案是使用空的中间类强制使用不同的名称:
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;
}
struct Ob{int v;};//在此处添加以允许验证所有成员的副本
结构A{oba;};
结构B:A{obb;};
结构A1:A{};//C中A的直径的中间类
结构C:A1,B{obc;};//用A1代替A
结构A2:A{};//D中A的直径的中间类
结构D:C,A2{//使用A2代替A
obd;
D(){}
D(常数D&_D):C(_D),A2(_D),D(_D.D){
};
内部主(内部ac,字符**av)
{
cout请通过引用传递双参数
向前传递可以,双参数作为参考传递
// The time series function which is t ^ 5
auto func(dual *t) {
return autodiff::forward::pow(*t, 5.0);
}
// gradient calculation which is at (t)
var func_gradient(dual *t) {
auto u = func(t); // the output variable u
auto ux = autodiff::forward::derivative(u, autodiff::forward::wrt(t), at(t)); // evaluate the derivative of u with respect to x
return (var) ux;
}
你能添加完整的编译器错误消息吗?哦,我没听懂,yee compiler error plz。也许这很有用:@rupesh.yadav:除非你尝试直接使用这些成员,否则不会有错误,例如D::method(){a=a();}
或D=D();D.a=a();
。没有办法做到这一点。这是警告告诉您的。有关direct base唯一不可访问的内容的解释,请参阅。是的,它可以编译。但是我们这里有没有虚拟基的多重继承。在这个复制构造函数中,您只定义如何复制B继承的A基。它不会复制A基直接从中继承,也不是从C继承的A基!这两个都是用默认构造函数初始化的!!!这根本不等于默认的复制构造函数。是的,我的第一个答案不准确。我已经完成了。你能用我在中提出的验证码测试你提出的解决方案吗我的回答开始于“如果你添加一个成员intv;
”?我已经尝试了你的解决方案,似乎其中一个基类a(D的直接基)是从错误的基类a(B的基)复制过来的。你能检查一下吗?我正在C++11模式下使用clang++3.4版,它阻止我按照你的建议将D对象直接转换为a对象。报告的错误是:从派生类“D”到基类“a”的转换不明确。我已经尝试过了,这对我来说似乎是合理的,但不幸的是,它在MinGW 4上都没有编译。8.1也不在微软Visual C++ 2013中。编译器都会产生类似的错误消息:“a”是“D”的模糊基础,而类“A”已经初始化了,建议的解决方案不编译。