0xBADF00
0xBADF00

Reputation: 1120

Multiple virtual inheritance

I found the below code in our code base at work, and I think it looks strange. The class RetainCounting is used for implementing reference counting.

1.Should the IProvider really derive from RetainCounting? Isn´t it better if it was just an abstract base class and then let the class that implements IProvider i.e. ProviderImpl derive from the "RetainCounting" instead (i.e. if it needs retain/release features)?

2.If we believe that IProvider should derive from RetainCounting, why do ProviderImpl needs to derive from "RetainCounting" as well, when the IProvider already has this inheritance?

class RetainCounting
{
public:
   virtual ~RetainCounting();
   void retain();
   void release();

private:
   // more code....
};

class IProvider : public virtual RetainCounting
{
public:
   virtual void doSomething() = 0;
};

class ProviderImpl : virtual private IProvider,
                     virtual public RetainCounting
{
public:
   void doSomething() override;
};

Upvotes: 1

Views: 86

Answers (2)

eerorika
eerorika

Reputation: 238441

2.If we believe that IProvider should derive from RetainCounting, why do ProviderImpl needs to derive from "RetainCounting" as well, when the IProvider already has this inheritance?

If it must inherit RetainCounting publicly, then yes it must inherit it because IProvider - and transitively it's own RetainCounting base - is inherited privately. But you may inherit IProvider non-virutally unless something inherits multiple IProvider derivatives.

If there is no need for the visibility difference, then you can simplify the design by getting rid of the virtual inheritance, and only inheriting IProvider.

class IProvider : public RetainCounting

class ProviderImpl : public IProvider // or private, depending on what you need

1.Should the IProvider really derive from RetainCounting? Isn´t it better if it was just an abstract base class and then let the class that implements IProvider i.e. ProviderImpl derive from the "RetainCounting" instead (i.e. if it needs retain/release features)?

If all derivatives of IProvider don't need to be reference counted, then IProvider shouldn't inherit RetainCounting and that should only be done in the derivative instead.

Interface usually means a class that has only pure virtual functions and no member variables. If IProvider inherits something that is not an interface, then it's not an interface itself.

If all defivatives of IProvider must be reference counted but you want IProvider to be an interface such as is usually implied with I-prefixed name, then what you could do is define an interface for reference counting. Let's call it IRetainCounting. Since the implementation is probably shared by many derivatives, you can create a base class that implements it. This causes you to need virtual inheritance.

class IRetainCounting
{
public:
    virtual ~IRetainCounting(){}
    virtual void retain() = 0;
    virtual void release() = 0;
};

class RetainCounting: public virtual IRetainCounting
{
public:
    void retain() override;
    void release() override;

private:
   // more code....
};

class IProvider : public virtual IRetainCounting
{
public:
    virtual void doSomething() = 0;
};

// option 1
class ProviderImpl : private IProvider,
                     public RetainCounting
{
public:
    void doSomething() override;
};

// option 2, you can keep BaseRetainCounting private if you want to
// I recommend this if there can be more than 1 implementation of IRetainCounting
// otherwise 1 is simpler
class ProviderImpl : private IProvider,
                     private RetainCounting,
                     public virtual IRetainCounting

The advantage: pure interfaces

The disadvantage: more code (but only a constant amount. The amount of boilerplate does not scale up with the number of derivatives.) and the need for virtual inheritance (which you need anyway for the visibility difference)

Upvotes: 1

Adrian Maire
Adrian Maire

Reputation: 14865

Should the IProvider really derive from RetainCounting? It is just a pure interface, shouldn´t the class that implements IProvider i.e. ProviderImpl derive from the "RetainCounting" instead?

Well, if you want IProvider to have retain() and release(), so yes, you could derive it from RetainCounting. That another derived class already has RetainCounting does not matter. So to summarize, the question is: Do IProvider need retain() and release() features?

2.If we believe that IProvider should derive from RetainCounting, why do ProviderImpl needs to derive from "RetainCounting" as well, when the IProvider already has this inheritance?

That IMO does not make sense in this specific case. You could easily carry this kind of double inheritance with diamond-like classes, but in this specific case I do not see any benefit.

Upvotes: 0

Related Questions