инициализация виртуальных базовых классов

Я работаю над тестом, и мне трудно понять это:

#include <iostream>

struct Car
{
 Car() : price(20000) {}
 Car(double b) : price(b*1.1) {}
 double price;
};
struct Toyota : public virtual Car 
{
 Toyota(double b) : Car(b) {}
};

struct Prius : public Toyota
{
 Prius(double b) : Toyota(b)  {}
};

int main(int argc, char** argv)
{
 Prius p(30000);

 std::cout << p.price << std::endl;

 return 0;
}

Возвращаемое значение равно 20 000, но на самом деле я не понимаю, почему:

Все подобъекты, представляющие виртуальные базовые классы, инициализируются конструктором самого производного класса. Если конструктор наиболее производного класса не указывает инициализатор памяти для виртуального базового класса V, то для инициализации подобъекта виртуального базового класса вызывается конструктор V по умолчанию.

И я попробовал другой способ создать конструктор в производном классе, но получил ошибки от компилятора.

Кто-нибудь дает объяснение и как создать такой конструктор?


person fabrice    schedule 31.08.2018    source источник


Ответы (2)


Удалить виртуальное наследование:

struct Car
{
 Car() : price(20000) {}
 Car(double b) : price(b*1.1) {}
 double price;
 virtual ~Car() = default;
};

struct Toyota : public Car 
{
 Toyota(double b) : Car(b) {}
};

Прямая трансляция

Toyota Является Car и не нуждается в виртуальном наследовании.

Прочтите здесь о виртуальном наследовании, если ваш тест посвящен виртуальному наследованию.

person Moia    schedule 31.08.2018

Просто добавьте mem-initializer для (косвенной) виртуальной базы:

Prius(double b) : Car(b), Toyota(b)  {}

Смотрите на coliru.

Виртуальное наследование гарантирует, что виртуальная база будет существовать только один раз в полном объекте. Для этого не может быть задачей какой-то промежуточной базы, которая может быть даже не единственной, которая просит об этом, инициализировать виртуальную базу: какая из них должна получить добро?
Вместо этого ctor разделен на два: один для инициализации всего, кроме виртуальных баз, будь они прямыми или косвенными, и который используется производными классами, а другой сначала инициализирует виртуальные базы, а затем делегирует все остальное первому, который тот призывал к созданию полного объекта.

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

person Deduplicator    schedule 31.08.2018
comment
Большое спасибо, я понял! - person fabrice; 31.08.2018