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.