Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/152.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/arduino/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 调用祖父母构造函数的虚拟继承而非多重继承_C++_Virtual Inheritance - Fatal编程技术网

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转换
a
Base
指针指向
B
指针


此外,我还想知道它为什么会起作用(我的意思是为什么a
B().ref==reobjectforb
):我认为
B()
中对default
a()
构造函数的隐式调用会在显式
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
};