Виртуальный класс в алмазном наследовании

Насколько я понимаю, использование 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 подавляет конструктор student как в endsem, так и в midsem, как создается один экземпляр student при создании объекта total?

  2. Теперь, когда я хочу создать другой класс, производный от endsem, будет ли создание объекта нового класса вызывать конструктор класса student, поскольку предполагается, что использование virtual подавляет его?


person user3656142    schedule 28.08.2019    source источник
comment
Не существует такой вещи, как виртуальные классы; класс может отображаться как виртуальный или не виртуальный базовый класс в иерархии. (Многие люди называют классы с виртуальными функциями виртуальными классами, но это полиморфные классы.)   -  person curiousguy    schedule 31.08.2019


Ответы (1)


Насколько я понимаю, использование виртуального подавляет конструктор базового класса и, следовательно, позволяет избежать создания экземпляров нескольких объектов базового класса.

Виртуальный применяется к отношению наследования; он подавляет вызов конструктора виртуального базового класса для любого промежуточного производного класса, независимо от того, названа ли эта база явно в 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 база Der2bis теперь доступна напрямую нет доступа к преобразование Der2bis -> PrivateBase производного в базовое из членов класса является заданным (преобразование по-прежнему недоступно из другого кода).

3) Это означает, что частные конструкторы могут использоваться только в том случае, если самый производный класс становится другом базового. Это означает, что некоторые классы могут быть производными, но тогда не будут иметь действительных определений конструктора:

class TheFriend;

class AllPrivate {
  AllPrivate ();
  AllPrivate (AllPrivate&);
  friend class TheFriend;
};

class TheFriend : virtual AllPrivate { };

Обратите внимание, что TheFriend может по умолчанию создавать свой подобъект базового класса (путем именования своего конструктора по умолчанию) только в силу того, что он является его другом.

Но вывести дальше не получится, даже при повторении приватной базы сделать ее доступной:

class MoreDerived : TheFriend, virtual AllPrivate {};

Здесь частная база становится доступной, но ее члены по-прежнему недоступны, MoreDerived не является другом и не может вызывать конструкторы базы, поэтому ни один из ее конструкторов, явно или неявно определенных, не может быть правильно сформирован.

person curiousguy    schedule 31.08.2019