Помимо проблем проектирования (которые явно существуют здесь), я полностью согласен с вашим рассуждением о том, что, поскольку Left
является абстрактным классом, никакой конструктор Left
никогда не должен будет вызывать какой-либо конструктор Base
, и поэтому он является нечетным что это требуется.
На самом деле, я тестировал ваш код с несколькими версиями компилятора, и он компилируется очень хорошо с gcc 7.1 и далее, с clang 3.4.1 и и далее со всеми доступными msvc версиями.
Итак, я предполагаю, что это была просто ошибка в более ранних версиях компилятора. Кто-нибудь может это подтвердить?
Также обратите внимание, что если вы измените virtual void leftsMethod() = 0;
на virtual void leftsMethod() {}
, чтобы Left
больше не был абстрактным, ошибка вернется, даже с последними версиями . И это вполне логично, так как теперь вы могли бы создавать экземпляр Left
, и, таким образом, конструктору Left
было бы до вызова одного из конструкторов Base
.
Возможное решение
Если вы не можете переключиться на более новый компилятор, и если вы не можете изменить реализацию Base
, это может быть рабочим решением для вас:
Определите фиктивный экземпляр где-нибудь CustomType
. Затем вы можете предоставить «обязательные» конструкторы по умолчанию, например:
class CustomType{};
class Base
{
public:
Base( CustomType& obj ) : refObj_( obj ) {}
private:
CustomType& refObj_;
};
static CustomType dummy;
class Left : public virtual Base
{
protected:
Left() : Base(dummy) {}; // note here
public:
virtual void leftsMethod() = 0;
};
class Right : public virtual Base
{
protected:
Right() : Base(dummy) {}; // and here
public:
virtual void rightsMethod() = 0;
};
class Bottom : public Left, public Right
{
public:
Bottom( CustomType& obj ) : Base( obj ), Left(), Right() {}
virtual void leftsMethod() override {}
virtual void rightsMethod() override {}
};
void test()
{
CustomType c;
Bottom b(c);
}
Это просто для того, чтобы компилятор был доволен, ваш аргумент, что эти конструкторы никогда не будут вызывать Base(dummy)
, по-прежнему сохраняется.
Обратите внимание, что Base
действительно должен иметь виртуальный деструктор! Я не знаю, если вы просто не включили это здесь для краткости или оно действительно отсутствует. Если этого не произойдет, очень плохая идея построить иерархию классов поверх нее.