钻石继承中的虚拟类

时间:2019-08-28 16:31:56

标签: inheritance multiple-inheritance virtual-inheritance diamond-problem

据我了解,使用virtual会抑制基类的构造函数,因此能够避免实例化基类的多个对象。

如果两个派生类的构造函数都被抑制,那么如何实例化基类的一个实例(从中派生虚拟类)?

如果抑制了基类的构造函数,当我有一个必须从其中一个虚拟类继承的新类时,基类的构造函数也将在那里被抑制吗?

我在下面用示例解释了我的问题。

class student{ 
    int rollNo;
    public : student(int a): rollNo(a) { }
    int getRollNo() {
        return rollNo;
    }
};
class midsem : virtual public student{
    float midSemMarks;
    public : midsem(int a, float b) : student(a), midSemMarks(b) { }
    float getMidSemMarks() {
        return midSemMarks;
    }
};

class endsem : virtual public student{
    float endSemMarks;
    public : endsem(int a, float b):student(a),endSemMarks(b) { }
    float getEndSemMarks () {
        return endSemMarks;
    }
};
class total : public midsem, public endsem{
    float totalMarks;
    public:total(int a, float b, float c) :student(a), midsem(a,b), endsem(a,c) { }
    float getTotal() {
        return midsem::getMidSemMarks() + endsem::getEndSemMarks();
    }
  1. 在上面的示例中,创建total的对象时,实例化了student的单个对象。 但是如果使用virtual限制了endsemmidsem中学生的构造函数,那么在创建student的对象时如何创建total的一个实例?

  2. 现在,当我想创建另一个从endsem派生的类时,将创建新类的对象,调用student类的构造函数,就像使用virtual应该抑制它?

1 个答案:

答案 0 :(得分:1)

  

据我了解,使用virtual抑制了   基类,因此能够避免   实例化基类。

虚拟适用于继承关系;它抑制了任何中间派生类对虚拟基类构造函数的调用,无论该基是否在ctor-init-list中显式命名(在这种情况下,这意味着您将在没有该规则的情况下调用该基的默认构造函数) )。

  

如果两个派生类的构造函数都被抑制,则如何   基类的一个实例(虚拟类从该实例开始)   是派生的?

虚拟基类是从派生程度最高的类(不是中间类)中初始化的,无论是否在该类ctor-init-list中明确提及。 >

像往常一样,不提及基类就意味着将调用默认构造函数。

这意味着这些成员,构造函数必须可以从大多数派生类作为非静态成员进行访问。

仅当通过有效的可访问转换可访问基类时,非静态成员才可在派生类中访问,因此:

1)虚拟基础的私有继承会使代码格式错误:

class PrivateBase {};
class Der : virtual PrivateBase {};
class Der2 : Der {};

(请记住,默认情况下,使用关键字class的成员和碱基是私有的。)

明确声明的特殊成员(构造函数,析构函数,赋值)遵循通常的规则,并且它们的定义必须有效,就像它们是显式编写的一样;因此,为了使Der2有效,默认构造函数的Der2();定义和Der2::Der2 () {}必须有效。

所以Der () {}的实际含义是Der () : PrivateBase () {}(有效),而Der2 () : PrivateBase(), Der() {}的格式错误。

2)由于虚拟继承固有的多种访问路径,并且由于仅需要可访问的路径,因此虚拟私有继承几乎永远不会阻止从以下类派生类:

class PrivateBase {};
class Der : virtual PrivateBase {};
class Der2bis : Der, virtual PrivateBase {};

Der2bis变体与Der2几乎类似,除了虚拟基础再次被继承,这几乎使语义差异几乎为零(某些数据结构的布局可能会更改),除了虚拟现在可以直接访问PrivateBase的{​​{1}}基,而没有给定从类成员获得Der2bis派生基转换的可访问性(仍然不能从其他代码访问此转换)。

3)这意味着只有当派生程度最高的类成为基础的朋友时,才能使用私有构造函数。这意味着某些类可以派生,但是没有有效的构造函数定义:

Der2bis -> PrivateBase

请注意,class TheFriend; class AllPrivate { AllPrivate (); AllPrivate (AllPrivate&); friend class TheFriend; }; class TheFriend : virtual AllPrivate { }; 只能通过成为其朋友来默认构造其基类子对象(通过命名其默认构造函数)。

但是即使重复私有基础使其可访问,进一步推导也会失败:

TheFriend

在这里,私有基础可以访问,但是其成员仍然不可访问,class MoreDerived : TheFriend, virtual AllPrivate {}; 不是朋友,并且不能调用基础构造函数,因此无论是隐式还是显式定义的构造函数都不能很好地使用形成。