简体   繁体   中英

Overriding non-virtual inheritance in C++

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:

  1. Make 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) .
  2. Implement my own version of 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?

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.

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.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM