Reputation: 2447
Suppose I have this minimal example:
class BaseClass {
void method1();
};
class Foo : public BaseClass {
void method1();
};
class Bar : public Foo {
void method1();
}
class Interface : public Foo {
};
class MyClass : public Interface, public Bar {
}
When implementing MyClass
, how can I tell the compiler that Bar
is extending the Foo
in Interface
? I keep getting compiler errors due to the ambiguous conversion.
Note: Foo
and Bar
are from a library, so I can't implement another interface just to handle this.
Upvotes: 0
Views: 59
Reputation: 25516
class Foo
{
public:
virtual ~Foo() { }
virtual void f() { std::cout << "foo!" << std::endl; }
};
class Bar : public Foo
{
public:
void f() override { std::cout << "bar!" << std::endl; }
};
Problem now is that you cannot inherit from Foo
in Interface
:
You cannot modify Bar
, thus you cannot make it inherit virtually, so even if Interface
did, you'd get two instances of Foo
in MyClass
. So my approach is having a reference to Foo within interface and provide an explicit cast to:
class Interface
{
Foo& foo;
protected:
Interface(Foo& foo) : foo(foo) { }
public:
operator Foo&()
{
return foo;
}
virtual ~Interface() { }
// this actually is only a short cut - you can always
// access Foo's f via cast as well!
// (so you can drop it, if you prefer)
virtual void f() { foo.f(); }
};
class MyClass : public Interface, public Bar
{
public:
MyClass() : Interface(*static_cast<Foo*>(this)) { }
using Bar::f;
};
Now you can use it as follows:
MyClass c;
Interface* i = &c;
Foo* f = &static_cast<Foo&>(*i);
// or, if you have not yet lost access to c, simply:
f = &static_cast<Foo&>(c);
Extension: If you need to be able to instantiate Interface
directly (not in form of a derived class), you can achieve this with some minor modifications to Interface
:
class Interface
{
Foo* foo; // raw pointer even in times of C++11 and smart pointers:
// need to be able to delete c o n d i t i o n a l l y
bool isOwner;
protected:
Interface(Foo& foo) : foo(&foo), isOwner(false) { }
public:
Interface() : foo(new Foo()), isOwner(true) { }
operator Foo&()
{
return *foo;
}
virtual ~Interface()
{
if(isOwner)
{
delete foo;
}
}
virtual void f() { foo->f(); }
};
Edit: While above would work in general, you would get in trouble if you try to delete an Interface
(not derived) via Foo
pointer. You can solve the issue as follows:
class Interface
{
Foo& foo;
protected:
Interface(Foo& foo) : foo(foo) { }
public:
operator Foo&()
{
return foo;
}
virtual ~Interface() { }
//virtual void f() { foo.f(); }
};
class MyFoo : public Interface, public Foo
{
public:
MyFoo() : Interface(*static_cast<Foo*>(this)) { }
virtual ~MyFoo() { }
//using Foo::f; // don't need, if dropping the short cut
};
class MyBar : public Interface, public Bar
{
public:
MyBar() : Interface(*static_cast<Foo*>(this)) { }
virtual ~MyBar() { }
//using Bar::f; // don't need, if dropping the short cut
};
While now Foo
inherits from Bar
, MyBar
does not from MyFoo
, so you cannot assign a MyBar
object to a MyFoo
pointer. But you can both assign (via the cast) to a Foo
pointer, which is, according to the discussion to question, your actual goal, so this should be fine...
Upvotes: 1