9

相关:“多级继承情况下的虚拟基类”有没有意义

我有一个可以继承的模板类,以提供一些选择功能。但是,它希望防止任何类进一步从继承它的任何东西继承。

以下似乎实现了这一点:

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

//simplify a bit:
#define Seal( x ) public virtual SealingClass< x >

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

class NewClass: Seal(NewClass) {};

如果我然后尝试再次继承 from NewClass,如:

class AnotherClass: public NewClass {};

然后创建所述类的实例:

AnotherClass a;

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

所以,一切都如我所愿!

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

#define Seal( x ) public SealingClass< x >

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

我知道virtual,在这种情况下,关键字意味着在可能存在多个实例的多重继承(例如菱形继承)的情况下,只定义了基类的一个实例,从而导致模棱两可的函数调用等。

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

谢谢 :)

4

1 回答 1

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
};

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

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


一些报价:

[class.base.init]/1

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

[class.base.init]/7

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

[class.base.init]/10

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

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

强调我的。

于 2013-04-29T21:59:16.580 回答