简体   繁体   中英

Call an interface function from an unknown derived class (multiple inheritance)

I have an array of Base* objects. This holds a bunch of derived objects, some of which may implement an Interface .

struct Base {
    virtual void doNotCallThis() { cout << "nooo" << endl; }
};

struct Interface {
    virtual void doThis() = 0;
};

// Example derived class
struct Derived : Base, virtual Interface {
    virtual void doThis() { cout << "yes" << endl; }
};

int main() {
    Base* b[1];
    b[0] = new Derived(); // Here would be a bunch of different derived classes
    ((Interface*)b[0])->doThis(); // Elsewhere, doThis() would be called for select array elements
    return 0;
}

Output:

nooo

I don't know the exact type of b[i] at run time, so I can't cast to Derived (it could be Derived2 , Derived3 , etc). I also can't use dynamic_cast if that's a solution. All I know is that, by the time I call doThis() , b[i] is a type that inherits from Interface . The way I attempted to call it above causes the wrong function to be called, eg. Base::doNotCallThis() .

How can I call it properly?

As other people have pointed out, you would probably do best to find a way to refactor your design so that casting isn't necessary.

But putting that aside, I can explain what's going wrong and how to correctly cast.

The problem with ((Interface*)b[0]) is that since Base and Interface are unrelated the compiler has to do a blind reinterpretive cast. Practically speaking that means in this situation the resulting pointer doesn't actually line up with the Interface part of the object. If you were to try static_cast<Interface*>(b[0]) you would find it doesn't compile - and that's a big hint that it's the wrong kind of cast to be making.

On the other hand, the compiler does know the relationship from Base to Derived and also from Derived to Interface . So as long as you know for sure that the object not only implements Interface but also is a Derived then you can do:

static_cast<Interface*>(static_cast<Derived*>(b[0]))->doThis();

However if your design has multiple different derived types which independently implement Interface then you might not be able to do that unless again you absolutely know what the derived type is at any time you go to make the call. - This is why refactoring it into a better class hierarchy is more desirable, since it's much less fragile and cumbersome to work with.

(As a side note, this issue points out why it's a great idea to never use raw/reintrepretive casts when moving up and down a class hierarchy. At least use static_cast since the can compiler better help you do it correctly.)

Writing an answer with the risk of being downvoted:

If we start with::

struct Base()
{
   virtual void SomeFunc();
};

struct Interface
{
   virtual void doThis();
}

then to create a bunch of derived functions from Base that are also interfaces, I'd do something like this:

struct BaseInterface : public Base, public Interface
{
  // Nothing here - this is just combining Base and Interface 
};

struct Base1 : public BaseInterface
{
   ... add stuff that Base1 has that isn't in Base.
};

struct Derived: public Base1
{
  ... some more stuff that isn't in Base1 
}

And then we use it in Main like this:

int main() {
    BaseInterface* b[1];
    b[0] = new Derived(); // Here would be a bunch of different derived classes
    b[0])->doThis(); // Elsewhere, doThis() would be called for select array elements
    return 0;
}

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