2015-03-27 1 views
0

En relation avec this question; le code suivant tente de cacher les constructeurs publics de chaque implémentation de composant spécifique tout en fournissant une fonction générique create sur chaque composant (l'implémentation de celui-ci fait toujours la même chose: communiquer via un canal avec un serveur). En utilisant l'héritage multiple j'essaye d'ajouter la fonctionnalité aux composants qui doivent accéder aux champs de composants. Comme je ne veux qu'une instance de g_component dans chaque composant, j'utilise l'héritage virtuel.Impossible d'appeler le constructeur de base dans la classe modèle à l'aide de l'héritage virtuel

La classe ressemble g_component ceci:

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; 
    } 
}; 

Ensuite, il y a le g_titled_component qui peut avoir un titre:

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 
    } 
}; 

Enfin, le g_button et sa mise en œuvre se présentent comme suit:

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>(); 
} 

Cela devrait être bon, comme Par l'héritage virtuel, le constructeur de g_component ne sera appelé qu'une seule fois. Le problème est que la compilation échoue où le constructeur parent est appelé dans le constructeur de 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 

Pourquoi ça marche pas? L'héritage virtuel de g_concrete ne devrait-il pas appeler le ctor de g_button, entraînant l'appel du ctor de g_component?

Répondre

0

Le code

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

est coulée g_concrete<g_button>*-g_button* tout g_button est une base inaccessible privée de g_concrete<g_button> en raison de class g_concrete: virtual T. Par conséquent, essayez de remplacer class g_concrete: virtual T { par class g_concrete: public virtual T {.

+0

Cela ne fait aucune différence puisque 'g_concrete' est défini dans' g_button'. Ne fonctionne pas non plus. – maxdev

0

Vous devez toujours construire virtual bases, même indirectes.

Vous n'êtes pas.

En particulier, g_concrete<g_button>: g_button: virtual g_component. Le ctor de g_concrete construit g_button, mais ne parvient pas à construire g_component. Et non, vous ne pouvez pas déléguer cette tâche à g_button: c'est le prix de l'héritage virtual. Ces messages d'erreur sont confus car g_concrete est à la fois la classe englobante et une base indirecte. Pourquoi l'virtual héritage n'est pas clair.

+0

Je dois utiliser l'héritage 'virtual', parce que je veux avoir plusieurs types de composants (disons' g_titled_component', 'g_colored_component' ou' g_bounded_component') que je peux utiliser pour étendre la fonctionnalité d'une sous-classe sans la réimplémenter. – maxdev

+0

@maxdev La solution la plus simple est d'avoir 'i_component' avec' virtual int get_id() = 0' dont vous héritez virtuellement. Puis, dans les classes finales, vous héritez non-virtuellement de 'x_component' qui implémente' i_component'. Cela a des pénalités d'abstraction, mais comme vous héritez virtuellement des classes abstraites, le problème de construction est éliminé. Une autre approche consiste à utiliser l'héritage linéaire basé sur un modèle, dans lequel vous passez votre type parent à chacun. Je suis incertain de votre conception pourquoi 'setTitle' est' virtual' en aparté. – Yakk