0

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?

Community
  • 1
  • 1
maxdev
  • 2,491
  • 1
  • 25
  • 50

2 Answers2

0

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 {.

Lingxi
  • 14,579
  • 2
  • 37
  • 93
  • Makes no difference as the `g_concrete` is defined within the `g_button`. Does not work either. – maxdev Mar 27 '15 at 13:41
0

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.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • I need to use `virtual` inheritance, because I want to have multiple types of components (say, `g_titled_component`, `g_colored_component` or `g_bounded_component`) which I can use to extend the funcitonality of a subclass without reimplementing it. – maxdev Mar 27 '15 at 13:39
  • @maxdev the easiest solution is to have `i_component` with `virtual int get_id() = 0` which you inherit from virtually. Then in final classes, you inherit non-virtually from `x_component` which implements `i_component`. This has abstraction penalties, but because you only virtually inherit from abstract classes, the construction problem is eliminated. Another approach is to use template based linear inheritance, where you pass in your parent type to each. I am uncertain from your design why `setTitle` is `virtual` as an aside. – Yakk - Adam Nevraumont Mar 27 '15 at 14:03