2015-03-27 1 views
0

Связано с this question; следующий код пытается скрыть общие конструкторы каждой конкретной реализации компонента, предоставляя общую функцию create для каждого компонента (реализация его всегда делает то же самое: общение через канал с сервером).Невозможно вызвать базовый конструктор в классе шаблонов с использованием виртуального наследования

Используя множественное наследование, я пытаюсь добавить функциональность к компонентам, которым необходимо получить доступ к полям компонентов. Поскольку мне нужен только один экземпляр g_component в каждом компоненте, я использую виртуальное наследование.

g_component класс выглядит следующим образом:

class g_component { 
protected: 
    uint32_t id; 

    g_component(uint32_t id) : 
      id(id) { 
    } 

    template<typename T> 
    class g_concrete: virtual T { 
    public: 
     g_concrete(uint32_t id) : 
       T(id) { // <----------- this fails compilation 
     } 
    }; 

    template<typename COMPONENT_TYPE, uint32_t COMPONENT_CONSTANT> 
    static COMPONENT_TYPE* createComponent() { 
     // write request: using the COMPONENT_CONSTANT 
     // read response: component_id is read from the response 
     if (response_successful) { 
      return new g_concrete<COMPONENT_TYPE>(component_id); 
     } 
     return 0; 
    } 
}; 

Тогда есть g_titled_component, что может иметь название:

class g_titled_component: virtual public g_component { 
public: 
    g_titled_component(uint32_t id) : 
      g_component(id) { 
    } 

    virtual ~g_titled_component() { 
    } 

    virtual void setTitle(std::string title) { 
     // this implementation must have access to g_component::id 
    } 
}; 

Наконец, g_button и его реализация выглядит следующим образом:

class g_button: virtual public g_component, virtual public g_titled_component { 
protected: 
    g_button(uint32_t id) : 
      g_component(id), g_titled_component(id) { 
    } 
public: 
    static g_button* create(); 
}; 

g_button* g_button::create() { 
    return createComponent<g_button, G_UI_COMPONENT_BUTTON>(); 
} 

Это должно быть хорошо, поскольку ugh виртуальное наследование, конструктор g_component будет вызываться только один раз. Проблема заключается в том, что компиляция терпит неудачу, когда родительский конструктор вызывается в конструкторе g_concrete:

In file included from src/ui/button.hpp:13:0, 
       from src/ui/button.cpp:12: 
src/ui/component.hpp: In instantiation of 'static COMPONENT_TYPE* g_component::createComponent() [with COMPONENT_TYPE = g_button; unsigned int COMPONENT_CONSTANT = 0u]': 
src/ui/button.cpp:18:58: required from here 
src/ui/component.hpp:71:54: error: 'g_button' is an inaccessible base of 'g_component::g_concrete<g_button>' 
    return new g_concrete<COMPONENT_TYPE>(component_id); 
                ^
src/ui/component.hpp: In instantiation of 'g_component::g_concrete<T>::g_concrete(uint32_t) [with T = g_button; uint32_t = unsigned int]': 
src/ui/component.hpp:71:54: required from 'static COMPONENT_TYPE* g_component::createComponent() [with COMPONENT_TYPE = g_button; unsigned int COMPONENT_CONSTANT = 0u]' 
src/ui/button.cpp:18:58: required from here 
src/ui/component.hpp:38:9: error: no matching function for call to 'g_component::g_component()' 
    T(id) { 
     ^
src/ui/component.hpp:38:9: note: candidates are: 
src/ui/component.hpp:27:2: note: g_component::g_component(uint32_t) 
    g_component(uint32_t id) : 
^
src/ui/component.hpp:27:2: note: candidate expects 1 argument, 0 provided 
src/ui/component.hpp:23:7: note: constexpr g_component::g_component(const g_component&) 
class g_component { 
    ^
src/ui/component.hpp:23:7: note: candidate expects 1 argument, 0 provided 
src/ui/component.hpp:23:7: note: constexpr g_component::g_component(g_component&&) 
src/ui/component.hpp:23:7: note: candidate expects 1 argument, 0 provided 
src/ui/component.hpp:38:9: error: no matching function for call to 'g_titled_component::g_titled_component()' 
    T(id) { 
     ^
src/ui/component.hpp:38:9: note: candidates are: 
In file included from src/ui/button.hpp:14:0, 
       from src/ui/button.cpp:12: 
src/ui/titled_component.hpp:30:2: note: g_titled_component::g_titled_component(uint32_t) 
    g_titled_component(uint32_t id) : 
^
src/ui/titled_component.hpp:30:2: note: candidate expects 1 argument, 0 provided 
src/ui/titled_component.hpp:22:7: note: g_titled_component::g_titled_component(const g_titled_component&) 
class g_titled_component: virtual public g_component { 
    ^
src/ui/titled_component.hpp:22:7: note: candidate expects 1 argument, 0 provided 

Почему это не работает? Не должно ли виртуальное наследование g_concrete вызвать ctor g_button, в результате чего получится вызов ctor g_component?

ответ

0

Код

g_button* g_button::create() { 
return createComponent<g_button, G_UI_COMPONENT_BUTTON>(); 
} 

бросает из g_concrete<g_button>* в g_button* в то время как g_button частный недоступный баз g_concrete<g_button> из-за class g_concrete: virtual T.

Поэтому, попробуйте изменить class g_concrete: virtual T { на номер class g_concrete: public virtual T {.

+0

Не имеет значения, поскольку 'g_concrete' определен в' g_button'. Не работает. – maxdev

0

Вам всегда нужно строить основания, даже непрямые.

Вы не являетесь.

В частности, g_concrete<g_button>: g_button: virtual g_component. Ctor g_concrete строит g_button, но не может построить g_component. И нет, вы не можете делегировать эту задачу g_button: это цена virtual наследования.

Сообщения об ошибках Ths запутывают, потому что g_concrete является одновременно охватывающим классом и косвенной базой.

Почему вы делаете virtual Наследование непонятно.

+0

Мне нужно использовать наследование 'virtual', потому что я хочу иметь несколько типов компонентов (например,' g_titled_component', 'g_colored_component' или' g_bounded_component'), которые я могу использовать для расширения функциональности подкласса, не переопределяя его. – maxdev

+0

@maxdev самым простым решением является наличие 'i_component' с' virtual int get_id() = 0', который вы наследуете практически. Затем в финальных классах вы наследуете не виртуально от 'x_component', который реализует' i_component'. У этого есть абстракционные штрафы, но поскольку вы только фактически наследуете от абстрактных классов, проблема строительства устранена. Другой подход заключается в использовании линейного наследования на основе шаблонов, где вы передаете каждому из своих родительских типов. Я не уверен в вашем дизайне, почему 'setTitle' является' виртуальным' как в стороне. – Yakk

Смежные вопросы