在C#中跨越继承链接构造函数非常方便且有用。在C ++中实现类似功能的最佳方法是什么?这就是我想表达的意思:
struct A
{
A(int p)
{
i = p;
}
int i;
};
struct B : virtual A
{
B(int q) : A(q)
{
}
};
struct C : virtual B
{
C(int r) : B(r) // call B::B() which in turn would call A::A()
{
}
};
有什么想法吗?
干杯, 查理。
答案 0 :(得分:3)
派生程度最高的类(即C
)负责构建所有虚拟基类。因此,C
可以初始化A
和B
:
C(int r) : A(r), B(r)
请注意,虚拟基类在任何非虚基类之前进行初始化。无法使B
初始化虚拟基类A
。
你可以一起破解某些东西,例如通过使虚拟基础A
默认可构造,然后给它一个B
可以在其构造函数中调用的“初始化”方法,但这样做可能会造成危险。当为B
基类子对象调用B
构造函数时,无法知道从C
实际派生的A
的其他基类是否已经存在已初始化(并且可能已使用A
)或者它是唯一尝试初始化A
的类。
答案 1 :(得分:2)
在C ++中,虚拟继承要求派生类型最多的构造函数显式调用所有虚拟基础的构造函数:
C( int r ) : A(r), B(r) {}
虽然您已明确声明需要虚拟继承,但使用虚拟继承并不常见,因此您可能需要解释用例。可能有一些替代方案不需要这样做,因此允许构造函数的链接。
如果您想知道派生类型最多需要调用构造函数,原因是virtual
继承意味着整个对象中只有一个这样的基类。现在,如果你考虑一个可能的关系:
struct base { base( int x ); /*...*/ };
struct d1 : virtual base {
d1() : base(1) {}
// ...
};
struct d2 : virtual base {
d2() : base(2) {}
// ...
};
struct final : d1, d2 {};
应该在base
内向final
的单个实例的构造函数传递什么值?两个不同的继承路径传递冲突的值,但是有一个对象要初始化。即使不同的调用没有冲突,使用单独的编译模型,编译器也无法知道,因此唯一的选择是完整的对象决定如何初始化虚拟基础。