14

I am trying to define interface types in C++ using abstract classes and implement them with concrete classes. The problem I am running into is that I cannot both inherit and interface from another interface and inherit the implementation from a base concrete class.

My goal is to be able to define a hierarchy of interfaces which may inherit from less complex base interfaces. I also want to be able to extend the implementation of interfaces by inheriting from concrete classes (like inheriting from TObjectA in the example below).

This is what I have. The error I am getting is "object of abstract class type "TObjectB" is not allowed". I believe I know why, which is because I didn't implement MethodA() in TObjectB. But I really want is to have the implementation provided by a base class (TObjectA) and still have interface hierarchies (IInterfaceB inherits from IInterfaceA). I also don't want to repeat all the inherited interface methods in my derived concreate classes. How can I do this?

class IInterfaceA 
{ 
public:
    virtual void MethodA() = 0; 
}; 

class IInterfaceB : IInterfaceA
{ 
public:
    virtual void MethodB() = 0; 
}; 

class TObjectA : public IInterfaceA 
{ 
public:
    void MethodA() { cout << "Method A"; }  
}; 

class TObjectB : public TObjectA, public IInterfaceB 
{ 
public:
    void MethodB() { cout << "Method B"; } 
}; 

void TestInterfaces()
{
    IInterfaceB* b = new TObjectB(); // error: object of abstract class type "TObjectB" is not allowed
    b->MethodB();
    delete b;
}
sysrpl
  • 1,559
  • 3
  • 15
  • 24
  • 2
    You need virtual base classes. E.g. [see here](http://stackoverflow.com/questions/4605556/when-virtual-inheritance-is-a-good-design/4606206#4606206) – CB Bailey Feb 22 '12 at 23:33
  • I've had this exact problem today. In my case, `IInterfaceB` and `TObjectB` were private things in a container while `IInterfaceA` and `TObjectA` were user-supplied. – Smiley1000 Mar 27 '22 at 18:54

2 Answers2

13

In your class hierarchy, TObjectB actually has two IInterfaceA base class subobjects: one inherited through IInterfaceB and one inherited through TObjectA. The MethodA() from each of them needs to be implemented.

You need to inherit from the interface classes using public virtual inheritance, which ensures there is only a single base class subobject of each interface class type:

class IInterfaceA 
{ 
public:
    virtual void MethodA() = 0; 
}; 

class IInterfaceB : public virtual IInterfaceA
{ 
public:
    virtual void MethodB() = 0; 
}; 

class TObjectA : public virtual IInterfaceA 
{ 
public:
    void MethodA() { cout << "Method A"; }  
}; 

class TObjectB : public TObjectA, public virtual IInterfaceB 
{ 
public:
    void MethodB() { cout << "Method B"; } 
}; 

void TestInterfaces()
{
    TObjectB b_object;
    IInterfaceB& b = b_object;
    b.MethodB();
}

Whether or not such complex class hierarchies are desirable is another matter altogether.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • When I use your code I get the following warning "Warning: 'TObjectB' : inherits 'TObjectA::TObjectA::MethodA' via dominance". Also when i change the test to use heap allocated objects I get a runtime assertion error and the execution stops: void TestInterfaces() { IInterfaceB* b = new TObjectB(); b->MethodB(); delete b; } – sysrpl Feb 22 '12 at 23:45
  • Your interface classes must have virtual destructors if you intend to polymorphically delete objects through them. As for the warning: avoid complex inheritance hierarchies. – James McNellis Feb 23 '12 at 00:02
  • Note that this might generate some quite horrible virtual pointers and bloat your objects, even though it's not really required. – Smiley1000 Mar 27 '22 at 18:55
1

Your problem is caused by the dreaded diamond inheritance. You've implemented TObjectA::IInterfaceA::MethodA but not IInterfaceB::IInterfaceA::MethodA.

My recommendation would be to make IIterfaceA and IIterfaceB completely independent. If that's not possible, you can look into virtual inheritance.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622