Reputation: 1103
is it possible to inherit the implementation of an interface without implementing it for each implementation?
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
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
Reputation: 171117
I've been using a similar setup in a project, and it works for me. It should be enough to do the following:
Give IBase
a virtual destructor. A virtual destructor is necessary for being able to delete through pointers to a base class.
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.
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