简体   繁体   中英

Interface Design and Inheritance in C++

I need to use C++ interface classes to implement an unmanaged DLL in C++. Suppose I have this class structure:

class IA
{
public:

    virtual void Foo() = 0;
    ...
};

class A : public IA
{
public:

    virtual void Foo() override { ... }
    ...
};

class IB
{
public:

    virtual void Bar() = 0;
    ...
};

class B : public IB
    , public A
{
public:

    virtual void Bar() { ... }
    ...
};

Now, if I have a pointer to the interface IB , this would not compile:

IB* b = ...;
b->Foo();

To make it work, I'd have to make IB inherit from IA , as such:

class IB : public IA
{
    ...
};

But then this also wouldn't compile, because now B is no longer a concrete class, and the compiler expects it to implement IA::Foo , even though it inherits from A .

You can fix this using virtual inheritance:

class A : public virtual IA { ... };
class IB : public virtual IA { ... };
class B : public virtual IB, public A { ... };

Which generates a new warning in VC++:

warning C4250: 'B' : inherits 'A::A::Foo' via dominance

As I understand it, this is because now there is more than one declaration of Foo .

How do I inherit interfaces and their concrete implementation correctly without these issues?

As you wrote, this does not compile:

IB* b = ...;
b->Foo();

Of course this does not compile, as IB doesn't have a Foo member. To access Foo , you would need a pointer to IA , but IB* cannot be cast to IA* .

But there's a point, where you get your pointer to IB . At that point (or somewhere up the lineage) some interface needs to know about the true B object, which could be cast to IA as well, not only to IB . At that point you can ask for an IA* , and use it as such.

Someone having an IB* might not even know, if the implementation of IB is also an IA , or not.


An other possibility would be to define a casting member on IB , that casts your pointer to IA* . Like this:

IA * GetAsIA() = 0;

IB implementations that are IA as well can return a valid pointer, other implementations might return nullptr.

Suppress C4250 in your compiler settings and forget about it.

I am not aware of any issues with inheritance via dominance. Other compilers I'm using never warn about it even at their highest warning levels. Googling for c++ inheritance dominance problem brings up only complaints about C4250, never a description of any actual problem with actual code. I conclude this is a non-issue.

As long as IB does not attempt to implement IA anywhere but A and you understand that B has an implementation of IB that is dependent on the implementation of A (since B 's implementation of IA is implemented by A ) you can safely ignore that warning.

The primary reason for the warning is that normally you only need to look up or down the inheritance hierarchy to find all implementations, however in this case you need to look laterally, from IB to A .

If you want to erase the warning, the answers of Suppressing C4250 in your compiler is an option.

However, I think your are doing a bad design.

  • Your "B" class depends on a concrete class ( "A" class ).
  • You are using multiple inheritance. This is very few times a good solution.

I think you should try to have a relation of Has-a instead of Is-a .

class IA
{
public:
    virtual void Foo() = 0;
    ...
};

class A : public IA
{
public:
    virtual void Foo() override { ... }
    ...
};

class IB
{
public:
    virtual void Bar() = 0;
    ...
};

class B : public IB
{
private:
    IA* ptrIA;
public:
    B(IA* ia): ptrIA(ia) {}

    virtual void Bar() { ... }
    void performeFoo() { ptrIA->Foo(); }
    ...
};

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