虚拟但不是多重继承来调用祖父构造函数
Virtual but not multiple inheritance to call grandparent constructor
我有这样的代码:
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() {}
};
由于该属性是引用,我认为我只能在构造函数中设置它,因此我需要在B()
中调用Base
构造函数。 我找到了两种方法:在A
中提供一个"前向"构造函数(但这意味着在所有可能继承的类中添加代码(:
A(const Ref& iRef): Base(iRef)
或使用虚拟继承:
class A: public virtual Base
第二个选项允许在实现中使用更直接的代码B
但我想知道我是否在一个丑陋的技巧中滥用虚拟继承,或者它是否是一个有效的用例。
- 在这种情况下,我可以使用虚拟继承吗?
- 如果不是,出于什么原因?
我发现的"意外"行为之一是,由于虚拟继承,无法将Base
指针static_cast
到B
指针。
此外,我也想知道它为什么有效(我的意思是为什么B().ref == refObjectForB
(:我认为在 B()
中对默认A()
构造函数的隐式调用会在显式Base
构造函数之后覆盖 ref
属性,但虚拟继承可能并非如此。
坚持继承层次结构,我可以看到的最佳选择是实现受保护的构造函数,这些构造函数将转发给Base
类。 保护构造函数可确保不能使用此构造函数构造(最终(实例,因此它只会在子类中用于初始化超类。
使用一些或多或少丑陋和危险的宏,这变得很容易编写:
#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
中的内容。要解决此问题,请执行以下操作之一:
- 如果只需要静态的东西:使用 CRTP 在具体的
Common
类型中指定A
/B
:然后Common<A>
可以使用A::...
,但与A
的具体实例没有任何关系 - 如果需要实例:在
Common
的构造函数中提供指针/引用(略有开销( - 将前两个解决方案放在一起:使用 CRTP,在
A
中实现包装器函数,并在B
中调用Common<A>
函数,Common<B>
通过额外参数提供this
(这是一个A*
或B*
(。 - 与上面相同,但是如果您在此指针参数上重载/模板化这些函数("函数上的 CRTP",如果您想这样称呼它(,类
Common
也可以是非模板化的(没有 CRTP(。代码胜于雄辩。(示例代码没有您的引用,专注于"公共类"。
从技术上讲,您可以使用虚拟继承来实现在最派生的类中提供引用的目标。
是的,这是一种设计气味。
您的类除了它们的直接基础之外,不需要知道任何东西(当出于其他原因需要虚拟继承时,虚拟继承是规则的例外(。
坚持提议的类层次结构,为了解决问题,使用"using-声明"将 Base 的构造函数带到类 A 的受保护部分就足够了,即:
class A: public Base
{
public:
A() : Base(refObjectForA) {}
virtual ~A() {}
protected:
using Base::Base;
};
- 在c++中使用向量时,如何调用构造函数和析构函数
- C++:考虑但不调用构造函数的特殊性
- 对象实例化调用构造函数的次数太多
- 我使用向量来创建类对象列表.初始化向量时如何使用参数调用构造函数?
- C ++:通过大括号调用构造函数?
- 不能调用构造函数
- 赋值 boost::intrusive_ptr 而不调用构造函数?
- 在模板化类的构造函数中调用构造函数
- 如何为 std::vector 分配内存,然后稍后为某些元素调用构造函数?
- 为什么从另一个构造函数内部调用C++构造函数不修改类变量?
- 静态 std::map instatiation 在类的方法中调用构造函数吗?
- 有没有一种简单的方法可以在对象向量上调用构造函数?
- 我不明白在这个例子中什么时候调用构造函数
- 调用c++构造函数的不同方法
- 调用构造函数与将内联常量定义为默认参数
- 如何通过 Rust FFI 调用C++构造函数?
- "new"运算符是否总是调用构造函数?
- 无法调用构造函数
- 使用 "()" 调用构造函数不同于"{}"
- 确定是调用构造函数还是强制转换运算符的因素