C++ 调用祖父母构造函数的虚拟继承而非多重继承
我有这样的代码:C++ 调用祖父母构造函数的虚拟继承而非多重继承,c++,virtual-inheritance,C++,Virtual Inheritance,我有这样的代码: class Ref {<undefined>}; Ref refObjectForA, refObjectForB; class Base { public: Base(const Ref & iRef) : _ref(iRef) {} virtual ~Base() {} const Ref & ref; }; class A: public Base { public: A() : Base(ref
class Ref {<undefined>};
Ref refObjectForA, refObjectForB;
class Base
{
public:
Base(const Ref & iRef) : _ref(iRef) {}
virtual ~Base() {}
const Ref & ref;
};
class A: public Base
{
public:
A() : Base(refObjectForA) {}
virtual ~A() {}
};
class B: public A
{
public:
B() : Base(refObjectForB) {} // won't compile: Base is not direct base of B
virtual ~B() {}
};
或使用虚拟继承:
class A: public virtual Base
第二个选项允许在B
实现中使用更直接的代码,但我想知道我是否在一个丑陋的技巧中滥用虚拟继承,或者它是否是一个有效的用例
- 在这种情况下我可以使用虚拟继承吗李>
- 如果没有,原因是什么李>
静态\u转换aBase
指针指向B
指针
此外,我还想知道它为什么会起作用(我的意思是为什么aB().ref==reobjectforb
):我认为B()
中对defaulta()
构造函数的隐式调用会在显式Base
构造函数之后覆盖ref
属性,但虚拟继承可能不是这样。如果您想坚持继承层次结构,我能看到的最佳选择是实现受保护的构造函数,并引用它们将转发到基
类。使构造函数受保护可确保不能使用此构造函数构造(最终)实例,因此它将仅在子类中用于初始化超类
使用一些或多或少丑陋和危险的宏,这变得很容易编写:
#define REF_FORWARD_CTOR(ClassName, DirectSuperClassName) \
protected: ClassName(class Ref &r) : DirectSuperClassName(r) {} \
public:
class A : public Base
{
REF_FORWARD_CTOR(A, Base)
public:
A() : Base(refObjectForA) {} // normal ctor
};
class B : public A
{
REF_FORWARD_CTOR(B, A)
public:
B() : A(refObjectForB) {} // normal ctor
};
另一种设计是让A
和B
都(直接)从Base
派生。然后,通过使用多重继承和“公共类”(可能是私有类)添加功能,具体取决于它们的用途:
class Base {
};
class Common {
// common stuff used by both A and B
};
class A : public Base, public Common {
// no further stuff here
};
class B : public Base, public Common {
// add more stuff, or put it in a common super-class again,
// if some classes want to inherit from B again
};
这种设计的问题是,Common
中的功能无法访问A
和B
中的内容。要解决此问题,请执行以下操作之一:
- 如果只需要静态内容:用于在具体的
Common
类型中指定A
/B
,类型:Common(示例代码没有引用,重点是“Common类”)
是的,您可以从技术上使用虚拟继承来实现在派生最多的类中提供引用的目标
是的,这是一种设计的味道
您的类不需要知道任何东西,只需要知道它们的直接基(当出于其他原因需要虚拟继承时,虚拟继承是规则的例外)。尝试“跳过”一代通常表示设计已损坏B
甚至不应该知道Base
-它应该只使用A
的API。我看不出这些参考中的要点,看起来有点像您想要实现的类型信息。您可以将“转发”构造函数放在受保护的节中,因此它只能在派生类中使用。虚拟基总是直接从派生类最多的构造函数构造,而不是从任何中间类构造函数构造。IOW:A::A()中对Base::Base()的调用在正在构造的对象是B时没有任何作用。@LightnessRacesinOrbit我同意你的评论,但在我的例子中,我的代码一般处理Base
对象及其ref
属性,A
和B
类是“客户”类。我的目标不是阻止Base
下面的几个继承级别,而是提供一种方法,为每个子类提供特定的ref
值。莱姆斯:是的,这是我的设计选择。n、 m:这至少解释了为什么它“有效”,谢谢!谢谢你的建议!关于在B
中使用类B:public A,public virtual Base
明确说明Base
的虚拟继承,您有什么看法?编辑:我不确定这一点:问题是在B
的ctor中初始化A
时,Base
的一个实例已经初始化。Base
的同一个实例随后被重新用于B
中Base
的虚拟继承。因此,在这种情况下,您不能将重新对象forb
放在基础中!但是当在B
的构造函数中初始化A
时,是否已经设置了reobjectfora
,然后虚拟继承“重用”了Base
的这个实例?或者是/可能是另一种情况,取决于B
的构造函数中超级构造函数调用的顺序?@leemes我在我的真实案例示例中添加日志,构造顺序是Base,A,B
。但是我认为Base
构造函数是在B
中首先调用的,因此A()
中的Base
构造函数没有被调用(只有一个Base
日志),因为Base
部分已经构造好了(参见相关的n.m.评论)。但这证实了这是一种设计气味:每个子对象上都有一个构造函数调用。使用虚拟继承时,虚拟基由派生最多的类初始化,而忽略层次结构中较高层次的初始化。正如我所写的,这意味着技术上还可以,但仍然有设计的味道
class Base {
};
class Common {
// common stuff used by both A and B
};
class A : public Base, public Common {
// no further stuff here
};
class B : public Base, public Common {
// add more stuff, or put it in a common super-class again,
// if some classes want to inherit from B again
};