This is similar to this question and this one, but I think (hope!) different enough to deserve an explanation.
I have a complex configuration framework, with decorator classes used to implement some common, simple actions (like flagging when a class Set accessor is called). I'm trying to introduce a new decorator (rather than a composition), which itself "should" inherit from that same common "Set-flagging" decorator.
I'm running into "ambiguous conversion from derived class to base class", and my attempts to work around it have failed. I'm missing something obvious, I'm sure.
Here's a very simple example, without all my framework stuff.
class A {
public:
template <class T> void Set(T& arg, T val);
bool Ready() const;
};
class B : private A {
// Does stuff where I want to flag Set() actions
};
class C : public B, public A {
// This class needs the B interface, and the Set()-flagging
public:
void SetParam(double val) { Set(param, val); }
private:
double param;
};
Note that I original used virtual inheritance of A, but in practice I need to keep the "Set-flag" for B distinct from the "Set-flag" for C, hence my attempt above.
The private inheritance above was my first attempt to avoid the ambiguity. I also tried introducing using directives in C:
class C : public B, public A {
// This class needs the B interface, and the Set()-flagging
using A::Set;
using A::Ready;
};
This doesn't change the error. I understand from searching that the ambiguity is caught before the public/private state is checked. But I thought that the explicit using
directives would resolve it. Why doesn't it? Do I need to go in and use A::Set(...)
or A::Ready()
explicitly everywhere?
Two solutions.
If you really want to keep the private and multiple inheritance:
class A {
public:
void Set() {};
bool Ready() const {};
};
class B : private A {
};
class C : public B, public A {
public:
void SetParam() { C::A::Set(); }
};
Or if that is not needed, then a simpler one:
class A {
public:
void Set() {};
bool Ready() const {};
};
class B : public A {
};
class C : public B {
public:
void SetParam() { Set(); }
};