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

C++为什么虚拟继承允许防止进一步继承?,c++,inheritance,virtual,C++,Inheritance,Virtual,相关的: 我有一个模板类,可以从中继承,以便传递一些select功能。但是,它希望防止任何类从继承它的任何对象进一步继承 以下似乎实现了这一点: template<typename Child> class SealingClass { public: /*public methods etc*/ private: SealingClass() {} friend Child; }; //simplify a bit: #de

相关的:

我有一个模板类,可以从中继承,以便传递一些select功能。但是,它希望防止任何类从继承它的任何对象进一步继承

以下似乎实现了这一点:

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

//simplify a bit:
#define Seal( x ) public virtual SealingClass< x >
如果我再次尝试从NewClass继承,如:

然后创建所述类的一个实例:

AnotherClass a;
我得到了期望的错误,因为SealingClass中的构造函数是私有的

所以,一切按我的意愿进行

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

#define Seal( x ) public SealingClass< x >
…我对另一个类的实例化现在可以正常工作了

我理解,在这种情况下,virtual关键字意味着在多重继承的情况下只定义基类的一个实例,例如菱形继承,其中可能存在基类的多个实例,从而导致函数调用不明确等

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


谢谢:

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

因此,私有ctor不会阻止派生类型NewClass初始化直接基类SealingClass,如果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
};
现在,如果SealingClass的ctor是private,则由于private访问说明符和非好友关系,不允许另一个class_virt调用此ctor

如果省略了基类的显式初始化,无论是虚拟的还是直接的,它都是默认初始化的[class.base.init]/8,也就是说,默认的ctor是隐式调用的,但您仍然必须有权访问该ctor,因此这与显式编写对默认ctor的调用相同

一些引语:

[class.base.init]/1

在类的构造函数定义中,直接和虚拟基子对象以及非静态数据成员的初始值设定项可以由ctor初始值设定项指定

[class.base.init]/7

一种mem初始值设定项,其中mem初始值设定项id表示一个虚拟基类,在执行非最派生类的任何类的构造函数时将被忽略

[class.base.init]/10

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

首先,并且仅对于大多数派生类的构造函数,虚拟基类按照它们在基类有向无环图的深度优先从左到右遍历中出现的顺序进行初始化,其中“从左到右”是派生类基类说明符列表中基类的出现顺序。 然后,直接基类按照它们在基说明符列表中出现的声明顺序进行初始化,而不考虑mem初始值设定项的顺序。
重点是我的。

仔细阅读上面的链接答案,听起来好像是因为实例化虚拟继承类的顺序,这是有道理的!IIRC您必须在最派生的类型中初始化虚拟基类,而在下一个派生类型中初始化非虚拟基类。我假设您也有一个私有副本构造函数?否则,您可以简单地让您的所有子构造函数使用它来构造SealingClass,完全绕过seal;最后一个引号位于第一位,并且仅对于最派生类的构造函数,虚拟基类按照它们在基类的有向无环图的从左到右的深度优先遍历中出现的顺序进行初始化。。对于了解这里发生的事情特别有用!
#define Seal( x ) public SealingClass< x >
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
};