Понимание виртуальных базовых классов и вызовов конструктора

Возможный дубликат:
Кто вызывает конструктор в виртуальном наследовании?
виртуальное наследование С++

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

#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?

Ответ 1

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

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

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

Ответ 2

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