Почему конструктор по умолчанию называется виртуальным наследованием?

Я не понимаю, почему в следующем коде, когда я инициализирую объект типа 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);
}

Ответ 1

При использовании виртуального наследования конструктор виртуального базового класса вызывается непосредственно конструктором самого производного класса. В этом случае конструктор daughter напрямую вызывает конструктор grandmother.

Так как вы явно не вызывали конструктор grandmother в списке инициализации, вызывается конструктор по умолчанию. Чтобы вызвать правильный конструктор, измените его на:

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

См. также Этот раздел часто задаваемых вопросов.