简体   繁体   中英

Unable to call base constructor in template class using virtual inheritance

Related to this question ; the following code tries to hide the public constructors of each specific component implementation while providing a generic create function on each component (the implementation of it always does the same: communcating through a pipe with a server).

By using multiple inheritance I'm trying to add functionality to components that needs to access the components fields. As I only want one instance of g_component within each component, I'm using virtual inheritance.

The g_component class looks like this:

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

Then there is the g_titled_component that can have a title:

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

Finally, the g_button and its implementation look like this:

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

This should be okay, as through the virtual inheritance, the constructor of g_component will only be called once. The problem is, that the compilation fails where the parent constructor is called within the constructor of 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

Why does this not work? Shouldn't the virtual inheritance of g_concrete call the ctor of g_button , resulting in the ctor of g_component getting called?

The code

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

is casting from g_concrete<g_button>* to g_button* while g_button is a private inaccessible base of g_concrete<g_button> due to class g_concrete: virtual T .

Therefore, try changing class g_concrete: virtual T { to class g_concrete: public virtual T { .

You always need to construct virtual bases, even indirect ones.

You are not.

In particular, g_concrete<g_button>: g_button: virtual g_component . The ctor of g_concrete constructs g_button , but fails to construct g_component . And no, you may not delegate this task to g_button : that is the price of virtual inheritance.

Ths error messages are confusing, because g_concrete is both the enclosing class and an indirect base.

Why you are doing virtual inheritance is not clear.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM