Reputation: 1181
I'm working with an external library that exposes a variety of pure virtual interfaces. I am attempting to wrap them with my own implementation so I can extend their functionality. The issue I'm coming into is that the ChildClass
doesn't virtually derive from the BaseClass
. I wrote up a small app that demonstrates this:
///
/// External Library
///
class BaseClass {
public:
virtual ~BaseClass() { }
virtual int Foo(void) = 0;
};
class ChildClass
: public BaseClass {
public:
virtual int Bar(void) = 0;
};
///
/// Internal code
///
class BaseClassImpl
: public virtual BaseClass {
public:
virtual int Foo(void) {
return 5;
}
};
class ChildClassImpl
: public virtual ChildClass
, public virtual BaseClassImpl {
public:
virtual int Bar(void) {
return 12;
}
};
int main(int, char* []) {
ChildClass* impl = new ChildClassImpl;
printf("%d, %d\n", impl->Foo(), impl->Bar());
return 0;
}
And the output the compiler gives me is this:
1>main.cpp(41): error C2259: 'ChildClassImpl': cannot instantiate abstract class
1> main.cpp(41): note: due to following members:
1> main.cpp(41): note: 'int BaseClass::Foo(void)': is abstract
1> main.cpp(9): note: see declaration of 'BaseClass::Foo'
Now conceptually I understand the problem. The compiler sees the "diamond problem" with ChildClassImpl
inheriting from BaseClass
from two different parents. There are two solutions that I can use that work:
ChildClass
virtually derive from BaseClass
(class ChildClass : public virtual BaseClass
). This removes the compiler error and turns it into a warning (main.cpp(38): warning C4250: 'ChildClassImpl': inherits 'BaseClassImpl::BaseClassImpl::Foo' via dominance)
.Foo()
within ChildClassImpl
and stop deriving from BaseClassImpl
.I did try modifying the external library to add the virtual keyword and that worked just fine. Unfortunately this library really is unmodifyable, so that's not an option. Option 2 works (it's what I'm doing now), but it ends up in some duplicated code. I don't want to have to re-implement a function I'm already overriding.
I understand that virtual inheritance tells the compiler to ensure there's only ever one copy of BaseClass
within the inheritance tree and that's why it works. However, I don't understand if that's really a limitation in this case. The external classes are pure virtual and should only have one vtable, with only one version of each function. The traditional diamond problem (does the compiler choose Child1::Foo
or Child1::Foo
?) doesn't really exist here because there are no duplicate functions.
I know that the right answer in this case is "you're doing it wrong", but I can't control the external library and I need my Impl
's to be used as if they are the originals. Is there anyway to override the compiler to allow it to see that Foo
was already overridden within my parent?
Upvotes: 0
Views: 84
Reputation: 206577
Is there anyway to override the compiler to allow it to see that
Foo
was already overridden within my parent?
With the class hierarchy you have, that statement is not true in one branch of the inheritance hierarchy.
I suspect you know how to resolve the compiler error. Just in case you don't...
Add
virtual int Foo(void) {
return BaseClassImpl::Foo();
}
int ChildClassImpl
to resolve your compiler problem.
Class names usually represent abstractions. Generic names like Base
and Child
don't provide a clue as to the abstractions you are dealing with. Without understanding what those abstractions are, it is difficult for me to suggest a class hierarchy that would make sense.
Upvotes: 2
Reputation: 32732
Add to your ChildClassImpl
class
virtual int foo(void) {
return BaseClassImpl::foo();
}
This will redirect any calls to ChildClass's foo (or its copy of BaseClass) to BaseClassImpl's.
Upvotes: 0