Когда вы фактически наследуете базовый класс, во всех случаях виртуально унаследованный базовый класс можно всегда рассматривать как непосредственный суперкласс так называемого «наиболее производного» класса.Измените ваш конструктор Derived3
следующим образом:
Derived3(std::string message) : Derived1(message), Derived2(message),
Base(message)
Base
на самом деле также является базовым классом вашего Derived3
, поскольку он фактически наследуется от Derived1
(и Derived2
).Вот что такое виртуальное наследование.
Если вы не хотите, чтобы Base
создавался по умолчанию, вам нужно вызвать соответствующий конструктор самостоятельно, здесь.
Даже если вы этого не делаетеявным образом объявить Derived3
наследующим от Base
, он наследует его виртуально, следовательно, вы можете вызвать его конструктор из Derived3
.
Обратите внимание, что если вы объявите Derived4
как подкласс Derived3
,этот конструктор Base
здесь не будет вызван.Derived4
будет фактически наследовать Base
и будет отвечать за его создание.
Что действительно происходит, когда у вас есть виртуально унаследованные классы, это то, что каждый конструктор, который вы объявляете, может рассматриваться как фактически приводящий к двум фактическим конструкторам, в действительности: конструктору, который отвечает за создание всех виртуально унаследованных классов, и конструктору, который этого не делает.Этот Derived3
конструктор, который вы объявили выше: в итоге вы получите два конструктора из этого.Два по цене одного: один, который будет строить Base
, и тот, который не будет.Тот, который будет создавать Base
, используется, когда Derived3
создается непосредственно, и является наиболее производным классом.Второй конструктор такой же, за исключением того, что он не будет создавать Base
, и он будет использован, если будет создан экземпляр подкласса Derived3
.Вы видите его как один конструктор, но компилятор выполняет гораздо больше работы, создает два из них и гарантирует, что правильный будет использован, когда что-то нужно будет построить.