Philipp Neufeld
Philipp Neufeld

Reputation: 1103

Is it possible to inherit the implementation of an interface

is it possible to inherit the implementation of an interface without implementing it for each implementation?

enter image description here

In the image above IBase and Ichild are classes having only pure virtual methods and Base implements the methods of IBase and Child implements the methods of IChild. Is it now somehow possible for Child to inherit the implementations of the methods of IBase via Base, so that Child does not have to implement these methods itself?

I tried to implement it like this:

struct IBase {
    virtual void do_something_Base() = 0;
};

struct IChild : public virtual IBase {
    virtual void do_something_Child() = 0;
};


struct Base : public virtual IBase {
    virtual void do_something_Base() { //implementation IBase method
        //do sth
    }
};

struct Child : public Base , public IChild {
    virtual void do_something_Child() { //implementation IChild method
        //do sth
    }
};

int main() {

    IBase* B = new Child;
    B->do_something_Base();

    delete B;

    return 0;
}

The problem with this code is that the copiler gives a warning:

warning C4250: 'Child': inherits 'Base::Base::do_something_Base' via dominance

Futhermore the program crashes at the line delete B. (If I use IChild* B instead of IBase* B the program does not crash. why is that?)

Thanks in advance

Upvotes: 2

Views: 206

Answers (2)

Serge Ballesta
Serge Ballesta

Reputation: 148890

The inherits via dominance is just a warning that can be safely ignored here because the dominance gives you the correct override of the method.

But the crash on delete is because the pointer to an object through one class and a derived one need not have same representation (*). And you forgot to add a virtual destructor in IBase and IChild while it is highly recommended for inheritable classes, and necessary to allow deletion through a pointer to the inherited class as stated by @Angew.

If you have good reasons not to have a virtual destructor (even if I cannot imagine one), you have to cast it to a Child * before calling delete on it. Moreover, as IBase is virtual, you must use a dynamic_cast:

delete dynamic_cast<Child>(B);

An alternative is to keep the original pointer that was returned via new and delete it instead of using the conversion to IBase*:

Child* C = new Child;
IBase *B = C;

B->do_something_Base();

delete C;  // deleting original pointer is safe

(*) just to be sure, just add to your code:

std::cout << "IBase*:" << B << " Child*:" << dynamic_cast<Child>(B) << std::endl;

Upvotes: 1

I've been using a similar setup in a project, and it works for me. It should be enough to do the following:

  1. Give IBase a virtual destructor. A virtual destructor is necessary for being able to delete through pointers to a base class.

  2. To be on the safe side, derive Child from IChild virtually as well. Since the I-classes have no data, there's no point in using them as non-virtual bases.

  3. Disable the warning, as it's basically telling that the compiler is doing exactly what you want it to do (that the implementation is inherited from the correct base class).

Upvotes: 2

Related Questions