Загадка инициализации виртуального базового класса

У меня есть следующая конструкция в статической библиотеке (часть механизма диспетчера, несвязанные детали удалены для краткости):

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
};
Другие вопросы по тегам