我有这样的代码:
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() {}
};
由于属性是引用,我想我只能在构造函数中设置它,所以我需要在Base
中调用B()
构造函数。
我发现了两种方法:在A
中提供“前向”构造函数(但这意味着在可能继承的所有类中添加代码):
A(const Ref& iRef): Base(iRef)
或使用虚拟继承:
class A: public virtual Base
第二个选项允许在B
实现中使用更直接的代码,但我想知道我是否在一个丑陋的技巧中滥用虚拟继承,或者它是否是一个有效的用例。
我发现的一个“意外”行为是,由于虚拟继承,static_cast
指向Base
指针的B
指针是不可能的。
此外,我也想知道为什么它有效(我的意思是为什么B().ref == refObjectForB
):我认为A()
中对默认B()
构造函数的隐式调用会覆盖{{显式ref
构造函数之后的1}}属性,但虚拟继承可能不是这样。
答案 0 :(得分:4)
如果你想坚持你的继承层次结构,我可以看到的最佳选择是实现受保护的构造函数,它们将引用它们转发到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
中的内容。要解决此问题,请执行以下操作之一:
A
类型中指定B
/ Common
:Common<A>
然后可以使用{{1但是,与A::...
A
的构造函数中提供指针/引用(略微开销)Common
和A
中实现包装函数,这些函数调用B
和Common<A>
中提供Common<B>
的函数(这是this
或A*
通过额外参数。B*
也可以是非模板化的(没有CRTP)(“CRTP on functions”,如果你想调用它就像那)。 Code speaks louder than words.(示例代码没有您的引用,并侧重于“公共类”。)答案 1 :(得分:2)
是的,您可以在技术上使用虚拟继承来实现在最派生类中提供引用的目标。
是的,这是一种设计气味。
你的类不需要知道除了它们的直接基础之外的任何东西(虚拟继承是规则的例外,当出于其他原因需要它时)。