c ++为什么虚拟继承允许防止进一步继承?

jsd*_*sdw 9 c++ virtual inheritance

相关:"多级继承情况下的虚拟基类"是否具有重要意义

我有一个可以继承的模板类,以便赋予一些选择功能.但是,它希望阻止任何类继承继承它的任何东西.

以下似乎实现了这一点:

template<typename Child>
class SealingClass
    {
    public:
    /*public methods etc*/
    private:
    SealingClass() {}
    friend Child;
    };

//simplify a bit:
#define Seal( x ) public virtual SealingClass< x >
Run Code Online (Sandbox Code Playgroud)

现在,我可以继承上面的类,如下:

class NewClass: Seal(NewClass) {};
Run Code Online (Sandbox Code Playgroud)

如果我再尝试继承NewClass,如:

class AnotherClass: public NewClass {};
Run Code Online (Sandbox Code Playgroud)

然后创建所述类的实例:

AnotherClass a;
Run Code Online (Sandbox Code Playgroud)

关于SealingClass私有的构造函数,我得到了所需的错误.

所以,一切都按照我的意愿行事!

但是,我注意到如果我virtual从定义中删除关键字..

#define Seal( x ) public SealingClass< x >
Run Code Online (Sandbox Code Playgroud)

..我AnotherClass现在的实例工作得很好.

我理解virtual在这种情况下,关键字意味着在多重继承(例如钻石继承)的情况下只定义了基类的一个实例,其中可能存在多个实例,导致模糊的函数调用等.

但是,为什么它会影响上述功能呢?

谢谢 :)

dyp*_*dyp 7

如果使用虚拟继承,则派生程度最高的类型必须初始化此虚拟基类.如果不使用虚拟继承,则直接派生类型必须进行初始化.

因此,私有ctor不会阻止派生类型NewClass初始化直接基类SealingClass,并且如果它没有被虚拟继承AnotherClass则不必初始化NewClass.


一些例子:

template<typename Child>
class SealingClass {
public: // for now
    SealingClass() {}
};

class NewClass : public SealingClass<T> {
public:
    NewClass() : SealingClass<T>() {} // allowed, SealingClass<T> is a
                                      //   direct base class
};

class AnotherClass : public NewClass {
public:
    AnotherClass() : NewClass() {}        // allowed, NewClass is a
                                          //   direct base class
    AnotherClass() : SealingClass<T>() {} // not allowed, SealingClass<T> is
                                          //   no direct nor a virtual base class
};


class NewClass_v : public virtual SealingClass<T> {
public:
    NewClass_v() : SealingClass<T>() {}   // allowed, SealingClass<T> is a
                                          //   direct base class
};

class AnotherClass_v : public NewClass_v {
public:
    AnotherClass_v() : NewClass_v() {}        // allowed, NewClass_virt is a
                                              //   direct base class
    AnotherClass_v() : SealingClass<T>() {}   // allowed, SealingClass<T> is a 
                                              //   virtual base class
};
Run Code Online (Sandbox Code Playgroud)

现在,如果ctor SealingClass是私有的,AnotherClass_virt由于private访问说明符而不是朋友,不允许调用此ctor .

如果省略了基类的显式初始化(​​无论是虚拟的还是直接的),它是默认初始化的([class.base.init]/8),也就是默认调用默认的ctor(但你仍然必须有)访问ctor,所以它与显式写入默认ctor的调用相同).


一些引言:

[class.base.init]/1

在类的构造函数的定义中,可以通过ctor-initializer指定直接和虚拟基础子对象和非静态数据成员的初始化程序.

[class.base.init]/7

在执行不是最派生类的任何类的构造函数期间,将忽略mem-initializer,其中mem-initializer-id表示虚拟基类.

[class.base.init]/10

在非委托构造函数中,初始化按以下顺序进行:

  • 首先,仅对于派生类最多的构造函数,虚拟基类按照它们出现在基类的有向非循环图的深度优先从左到右遍历的顺序进行初始化,其中"从左到右" "是派生类base-specifier-list中基类出现的顺序.
  • 然后,直接基类按声明顺序初始化,因为它们出现在base-specifier-list中(无论mem-initializers的顺序如何).

强调我的.