3

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?

Zeenobit
  • 4,954
  • 3
  • 34
  • 46
  • @DieterLücking It was wrong. Thanks for spotting it. I fixed it. :) – Zeenobit Aug 06 '15 at 18:02
  • [Here is an answer that explains C4250](http://stackoverflow.com/questions/2190416/what-does-c4250-vc-warning-mean). If you are okay with that complication then it should work fine. – Guvante Aug 06 '15 at 18:06
  • @Guvante Given the fact that I'm using virtual inheritance to inherit interfaces, I don't think I would run into that sort of complication. So you would say it's safe to just disable the warning? – Zeenobit Aug 06 '15 at 18:16

4 Answers4

2

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.

Peter B
  • 416
  • 2
  • 7
  • While I think this is the safest approach, I don't think this solution will scale well for a relatively large project. I think ignoring the warning and enforcing a proper interface pattern is the better alternative for my case. – Zeenobit Aug 06 '15 at 21:13
1

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.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
0

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.

Guvante
  • 18,775
  • 1
  • 33
  • 64
0

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(); }
    ...
};
blashser
  • 921
  • 6
  • 13