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

Есть ли (практический) способ обойти нормальный (виртуальный) порядок вызова конструктора?

Пример:

class A
{
    const int i;

public:
    A()
      : i(0)
    { cout << "calling A()" << endl; }

    A(int p)
      : i(p)
    { cout << "calling A(int)" << endl; }
};

class B
    : public virtual A
{
public:
    B(int i)
      : A(i)
    { cout << "calling B(int)" << endl; }
};

class C
    : public B
{
public:
    C(int i)
      : A(i), B(i)
    { cout << "calling C(int)" << endl; }
};

class D
    : public C
{
public:
    D(int i)
      : /*A(i), */ C(i)
    { cout << "calling D(int)" << endl; }
};


int main()
{
    D d(42);
    return 0;
}

Вывод:

вызов A ()
вызов B (int)
вызов C (int)
вызов D (int)

То, что я хочу получить, выглядит примерно так:

вызов A (int)
вызов B (int)
вызов C (int)
вызов D (int)


Как видите, задействовано виртуальное наследование, которое приводит к тому, что конструктор D сначала вызывает конструктор A, но поскольку параметр не указан, он вызывает A (). Есть const int i, который требует инициализации, поэтому у меня проблема.

Я хотел бы скрыть подробности наследования C, поэтому я ищу способ избежать вызова A (i) в списке инициализации конструктора D (и каждого производного). [править] В этом конкретном случае я могу предположить, что существуют только не виртуальные дочерние классы C с одним наследованием (так как D - один). [/ Править]

[править]

Виртуальные базовые классы инициализируются до инициализации любых не виртуальных базовых классов, поэтому только самый производный класс может инициализировать виртуальные базовые классы. - Джеймс МакНеллис

В том-то и дело, что я не не хочу, чтобы самый производный класс вызывал конструктор виртуального базового класса. [/ edit]

Рассмотрим следующую ситуацию ( не представлен в примере кода выше ):

  A
 / \
B0  B1
 \ /
  C
  |
  D  

Я понимаю, почему C должен вызывать ctor A (неоднозначность), когда вы создаете экземпляр C, но почему D должен вызывать его при создании экземпляра D?

11
задан Lightness Races with Monica 10 February 2012 в 13:29
поделиться

3 ответа

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

Это потому, что вы говорите, что виртуальная база является общей для всех классов, производных от нее для экземпляра объекта. Поскольку конструктор может быть вызван только один раз для данного экземпляра объекта, вы должны явно вызвать конструктор в наиболее производном классе, потому что компилятор не знает, сколько классов совместно используют виртуальную базу (перефразировано (вероятно, плохо) из Язык программирования C ++ 3-е издание, раздел 15.2.4.1). Это связано с тем, что компилятор запускается с конструктора самого базового класса и работает с самым производным классом. Классы, которые наследуются от виртуального базового класса напрямую, по стандарту не будут вызывать конструктор своих виртуальных базовых классов, поэтому он должен вызываться явно.

7
ответ дан 3 December 2019 в 10:43
поделиться

Я понимаю, почему C должен вызывать ctor of A (двусмысленность), когда вы создать экземпляр C, но почему D должен вызывать его при создании экземпляра D?

По той же причине, по которой C должен его вызывать. Это не проблема двусмысленности, это факт, что конструктор A должен вызываться только один раз (поскольку это виртуальная база).

Если вы надеялись, что C сможет инициализировать конструктор A, то что, если класс D унаследует C и другой класс, который в конечном итоге унаследует A?

2
ответ дан 3 December 2019 в 10:43
поделиться

На parashift c++-faq-lite этот вопрос изложен.

-1
ответ дан 3 December 2019 в 10:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: