Загадка инициализации виртуального базового класса
У меня есть следующая конструкция в статической библиотеке (часть механизма диспетчера, несвязанные детали удалены для краткости):
class Base {
protected:
Base(Connection* conn = nullptr) : myConn(conn) {;} // = nullptr fixes the problem
Connection* myConn;
};
class Handler : virtual public Base {
public:
virtual void handleMessage(InputStream&) = 0;
protected:
Handler(int id) : myId(id) {;} <<<<< Error <<<<<<<
const int myId;
};
template<class EventType>
class TypedHandler : public Handler
{
protected:
TypedHandler() : Handler(EventType::ID) {;}
virtual void onEvent(const EventType&) = 0;
private:
virtual void handleMessage(InputStream& message)
{
EventType event(message);
onEvent( event );
}
};
Я полностью осознаю, что самый производный класс должен инициализировать базовый класс, который будет выглядеть следующим образом:
class A : public TypedHandler<SuperEvent>
, public TypedHandler<DuperEvent>
{
public:
A(Connection* conn) : Base(conn) {}
void onEvent(const SuperEvent&)
{ ... }
void onEvent(const DuperEvent&)
{ ... }
};
Но я получаю "ошибку C2512: нет подходящего конструктора по умолчанию, доступного виртуального базового класса" в отмеченной позиции (VS 2012, MSVC++ 11), даже при том, что Handler никогда не предназначался для самого производного...
Идеи?
Изменить: разрешив создание конструктора по умолчанию (через Connection* conn = nullptr
в конструкторе), это работает. По ссылке Игоря, конструктор по умолчанию не будет вызываться в конструкторе Handler, поскольку Handler является виртуальным.
Edit2: установив приватный конструктор по умолчанию для виртуального базового класса и установив два непосредственных подкласса в качестве друзей + конструктор не по умолчанию в качестве защищенного, он не только компилируется, но и происходит сбой компиляции, если самый производный класс не инициализирует виртуальный базовый класс правильно. Все галочки отмечены галочкой!:)
1 ответ
Эта проблема исправлена в clang 3.4, но не ранее. Учитывая, что это ошибка компилятора или, по крайней мере, спорная черта компилятора, и что Base(Connection& conn)
защищен, вы можете использовать обходной путь условной компиляции, например
class Base {
protected:
#if HAVE_BUG_GCC19249
Base(Connection& conn = _workaround_bug_gcc19249_) : myConn(conn) {;}
#else
Base(Connection& conn) : myConn(conn) {;}
#endif
Connection& myConn;
#if HAVE_BUG_GCC19249
static Connection _workaround_bug_gcc19249_;
// ... conditional definition in implementation file.
#endif
};