Чому конструктор за замовчуванням викликається у віртуальному успадкуванні?


79

Я не розумію, чому в наступному коді, коли я інстанцирую об'єкт типу daughter, grandmother()викликається конструктор за замовчуванням ?

Я думав, що або grandmother(int)конструктор слід викликати (щоб дотримуватися специфікації конструктора мого motherкласу), або цей код взагалі не повинен компілювати через віртуального успадкування.

Тут компілятор мовчки викликає grandmotherконструктор за замовчуванням в мою спину, тоді як я ніколи про нього не просив.

#include <iostream>

class grandmother {
public:
    grandmother() {
        std::cout << "grandmother (default)" << std::endl;
    }
    grandmother(int attr) {
        std::cout << "grandmother: " << attr << std::endl;
    }
};

class mother: virtual public grandmother {
public:
    mother(int attr) : grandmother(attr) {
        std::cout << "mother: " << attr << std::endl;
    }
};

class daughter: virtual public mother {
public:
    daughter(int attr) : mother(attr) {
        std::cout << "daughter: " << attr << std::endl;
    }
};

int main() {
  daughter x(0);
}

Який компілятор (і версія)? З якими аргументами ви його склали?
орлп

gcc 4.6.3 20120306 (Red Hat 4.6.3-2) на Fedora 15. Аргументами є: -O0 -g3 -Стіна -c -fmessage-length = 0
Саймон Десфарж

g ++ 4.1.2 має таку ж проблему: codepad.org/L0jBXfSP
orlp

Знімок Ubuntu 4.7 із помилками -Wall -pedantic-відтворює це.
juanchopanza

Відповіді:


85

При використанні віртуального успадкування конструктор віртуального базового класу викликається безпосередньо конструктором самого похідного класу. У цьому випадку daughterконструктор безпосередньо викликає grandmotherконструктор.

Оскільки ви явно не викликали grandmotherконструктор у списку ініціалізації, буде викликаний конструктор за замовчуванням. Щоб викликати правильний конструктор, змініть його на:

daugther(int attr) : grandmother(attr), mother(attr) { ... }

Див. Також цей розділ поширених запитань .


2
Це абсолютно має сенс, дякую! Усі конструктори в ієрархії викликаються з останнього класу, а не з їх відповідного дочірнього класу. Ніколи про це не думав. Специфікація C ++ іноді може бути складною ...
Aurelien Ribon

Дякую ! Тож у випадку віртуального успадкування найкраще зробити це вручну викликати всі конструктори ланцюжка.
Саймон Десфарж

1
@Xriuk Він відноситься до конструкторів класів, які успадкували за допомогою віртуального успадкування.
інтержой

1
це означає, що бабусю покличуть двічі? що відбувається із дзвінком до бабусі всередині матері?
Youda008,

6
@ Youda008 Це буде викликано один раз. Виклик від motherбуде проігноровано, якщо тільки ви motherне створили екземпляр, а не похідний клас.
інтержой
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.