Понимание виртуальных базовых классов и вызовов конструктора - PullRequest
13 голосов
/ 24 июня 2011

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

#include <cstdio>
#include <string>
using std::string;

struct A{
    string s;
    A() {}
    A(string t): s(t) {}
};

struct B: virtual public A{
    B(): A("B"){}
};

struct C: virtual public A {};

struct D: public B, public C {};

struct E: public C, public B {};

struct F: public B {};

int main(){
    D d;
    printf("\"%s\"\n",d.s.c_str());
    E e;
    printf("\"%s\"\n",e.s.c_str());
    F f;
    printf("\"%s\"\n",f.s.c_str());
    B b;
    printf("\"%s\"\n",b.s.c_str());
}

Какие результаты

""
""
""
"B"

Я не был уверен, что произойдет в первых двух случаях, но для третьего по крайней мере яожидал, что на выходе будет «B».Так что теперь я просто растерялся.Каковы правила для понимания, как вызывается конструктор A?

Ответы [ 2 ]

9 голосов
/ 24 июня 2011

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

Обновление: Извините, что пропустил ваш главный вопрос! Благодаря ildjarn.

Однако ваш B наследует фактически от A. Согласно стандарту (10.1.4 в FIDS), «для каждого отдельного базового класса, который указан виртуальный, наиболее производный объект должен содержать один подобъект базового класса этого типа». В вашем случае это означает, что при создании базы ваш класс F немедленно вызывает конструктор A по умолчанию, а не B.

7 голосов
/ 24 июня 2011

Виртуальные базовые классы всегда построены самым производным классом.

...