Should I avoid multiple implementation inheritance?

Viewed 856

I would like to define interfaces for different properties of my classes that can be accessed from external methods/classes.

  • I use multiple implementation inheritance (= inheritance from concrete classes which opposed to interface inheritance) which is considered a bad practice (point 3 from here).

  • I use inheritance for code reuse. As said here, it is better to use composition over inheritance for code reuse. But with composition, all my MyObj1,MyObj2,...,MyObj1000 will have the same get and set methods, while I have to reimplement them really rarely.

Is this scenario is perfect illustration of situation when multiple implementation inheritance for code reuse is good or this code completely wrong and I should use some clever syntax / patterns to avoid such design? I ask this question because I believe in latter.

#include <string>
#include <iostream>

// interface of object with name
class BaseName {
public:
    virtual void setName(const std::string& val) { name = val; }
    virtual std::string getName() const { return name; }
private:
    std::string name;
};

// user of interface of objects with name
void nameUser(BaseName* b) {
    std::cout << b->getName() << std::endl;
}

// interface of object with id
class BaseID {
public:
    virtual void setID(int val) { id = val; }
    virtual int getID() const { return id; }
private:
    int id = 0;
};

// user of interface of objects with id
void idUser(BaseID* b) {
    std::cout << b->getID() << std::endl;
}

class MyObj1 : public BaseID, public BaseName {
public:
    void setName(const std::string& val) override { 
        /* update internal state that depends on name. this is why "virtual" is required */
        BaseName::setName(val);
    }

    /* methods and fields specific to MyObj1 */
};

// MyObj2,...,MyObj999

class MyObj1000 : public BaseID, public BaseName {
public:
    /* methods and fields specific to MyObj1000 */
};

int main() {
    MyObj1 o1;
    o1.setName("xxx");
    o1.setID(18);

    MyObj1000 o2;
    o2.setName("yyy");
    o2.setID(-738);

    nameUser(&o1);
    nameUser(&o2);
    idUser(&o1);
    idUser(&o2);
}
2 Answers

You should only inherit if your derived class IS-A base class, that is it makes sense for it to act in your system as the class it inherits from. Where multiple inheritance comes in is where your derived class exists in multiple "domains", for instance you might have a bird class that is also serializable, you would inherit from both animal and serializable, and it would be OK to inherit implementation from each.

But the fact that you have 1000 derived classes is a Code Smell to me. You perhaps should step back and take a wider look at your design and what you're trying to achieve. Knowing more about that would help us give better answers.

You should only inherit if your derived class IS-A base class, that is it makes sense for it to act in your system as the class it inherits from.

That said multiple inheritance is perfectly fine in C++. A class can have multiple IS-A base classes. It's also good practice with so called mix-in classes or interfaces. Classes that add a bit of functionality to the class without bothering the rest of the class much. For example inheriting a Serializable base class.

One thing I would try to avoid though is the diamond problem. That is inherit two or more classes that in turn inherit from the same base class. For example

class Base { int base; };
class A : public Base { };
class B : public Base { };
class X : public class A, B { };

In such situation it is hard to understand when X.base comes from and easy for A and B to make different use of the Base class. That will lead to hard to debug errors.

Related