开发者

C++ interfaces and inheritance

开发者 https://www.devze.com 2023-02-23 06:59 出处:网络
I want to have an interface IA and another that extends it IB. A then implements IA, and B inherits A and also implements IB.

I want to have an interface IA and another that extends it IB.

A then implements IA, and B inherits A and also implements IB.

However when compiling B gets errors saying the IA stuff is undefined, even though A defined it all :(

class IA
{
public:
    virtual ~IA(){}
    virtual void foo()=0;
};
class IB : public IA
{
public:
    virtual void bar()=0;
};


class A : public IA
{
public:
    A();
    vo开发者_如何学运维id foo();
};
class B : public A, public IB
{
public:
    B();
    void bar();
};

error C2259: 'B' : cannot instantiate abstract class

due to following members:

'void IA::foo(void)' : is abstract


Take a look at the C++ FAQ, from the following point onwards: https://isocpp.org/wiki/faq/multiple-inheritance#mi-diamond

It explains the "dreaded diamond" and virtual inheritance in some detail.


(No, A does not define anything. You declared A() and void foo(), but you did not define them.)

The real problem is your multiple inheritance.

       B
     /   \
   A      IB
  /         \
IA          IA

As you can see, you have two "versions" of IA in your inheritance tree, and only A implements void IA::foo (though, as I noted above, this will give you a linker error as you didn't define the implementation).

void IB::IA::foo() remains unimplemented; thus, B itself "inherits the abstractness" and you can't instantiate it.

B will have to implement void foo() as well, or you might be able to use virtual inheritance to hack around it.


This is the real fully justified case for virtual inheritance which is not always a design smell.

In the case of parallel hierarchies interface / implementation, every inheritance relation of the form "any class -> interface" should be marked virtual: class A : public virtual IA; class B : public virtual IB, public A and class IB : public virtual IA.

This way, likely (implementation dependant but at least conceptually), an extra pointer is stored in each virtually derived class to know where it should find its virtual base. Class A, B and IB will have a pointer to IA, and class B will have a pointer to IB. Each virtual base will also have its own vtable.

The "dreaded diamond" point of view is graphically nice, but the point is that derived classes should know where the base class they will use reside, and that is where virtual inheritance kicks in. You clearly need a vtable per interface here, and virtual inheritance allows you to do just that.

Then you can continue paralleling, and add extra classes C, IC, and so on, just remember:

Whenever you inherit an interface, inherit virtually.

By the way, COM classes have similar design.


You have two copies of foo(), one inherited from IB::IA and one from A::IA. Only one of those have a non-abstract version in A.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号