Is it bad design to have an abstract class inherit from another abstract class? I have a single base node (class BaseNode) and 3 possible child node types (Sink, Process, and Source).

Is the inheritance between BaseNode and SinkNode good practise? If not what is another solution?

class BaseNode (metaclass=ABCMeta):
   def _Execute(self) -> bool:

   def _Configuration(self) -> bool:
   def __init__(self, nodeID) 

class SinkNode(BaseNode, metaclass=ABCMeta):
    def Type():
        return NodeType.SINK

    def __init__(self, nodeID):

class DataWriteNode(SinkNode): 
    def _Execute(self): 
    def _Configuration(self):
    def __init__(self, nodeID): 

3 Answers 3


Yes, it is generally a bad design; however, I am sure they may be a case or two where it is appropriate, but I haven't seen one.

In fact, use of abstract base classes, even one, is generally bad. Inheritance is for polymorphism, not code resuse; and composition should be favored over inheritance to begin with.

With that said, we work in the real world, and tools and are here to make working software, not to be used in a exercise of spiritual purity. In some cases, it just makes practical sense to use an abstract base class for code reuse; however, it should be done with great reservation. Here are my personal rules for abstract base class use:

  1. Abstract base class can save a great deal of coding in at least 3 decedent classes
  2. The abstract base class's methods do not call any of its other methods
  3. The abstract base class aggregates multiple interfaces
  4. The abstract base class' behavior is easily overridable
  5. The abstract base class should NEVER be referenced by anyone except its inheritors, only reference the aggregated interfaces externally.

I do not think your particular use case warrants even one abstract class, never the less two.

If I were you, I would just declare several interfaces, one for each shared method, then implement everything individually in the sink and datawrite nodes. This will give you much more flexibility in the future.

Let me give you an example as to why you should not be using abstract base classes and inheritance haphazardly:

Let's say your boss tells you to make a game, the player class needs to be able to shoot any of three types of enemies: goblins, trolls, and elves. Since they act largely the same, you define a abstract Enemy class which they all inherit from. Now you make your player class which has a shoot method taking the abstract Enemy class as an argument.

This looks great, and you've saved a lot of time and code... until your boss adds a requirement that if you shoot a golden box, your health refills... obviously your golden box cannot inherit from your your Enemy class, it shares nothing in common with them except the ability to be shot. Now you have to implement two versions of the Shoot method... there goes code reuse.


I don't think it's bad design. In the following scenario, I think it is appropriate.

class IControl
    virtual void draw() = 0;

class IButton: public IControl
    virtual void click() = 0;

class WinButton: public IButton
    void draw() { cout<<"Windows button drawn"<<endl; }
    void click() { cout<<"Windows button clicked"<<endl; }

Please point me out if I am wrong. Thanks!

  • 1
    Please describe why you think it's appropriate; don't just dump code
    – Jan Doggen
    Sep 25, 2019 at 8:07
  • I up-voted because this type of inheritance between interfaces is exactly what you see in the .NET libraries when it comes to collections. IList inherits from ICollection which inherits from IEnumerable.
    – asaf92
    Feb 14, 2020 at 11:23

Is it bad design to have an abstract class inherit from another abstract class?

I don't think so. I have been using it in a large C++ application at work for more than twenty years.

I'll present a simplified view of the kinds of entities a CAD application would deal with.

There's usually a common base class that deals with names of objects, to attach user specific data to an object, etc.. However, there are pure virtual functions to make a copy of the object, to write an object to a file or stream and read from a file or stream, etc.

class BaseEntity

     void setName(std::string const& name);
     std::string const& getName() const;

     void setAttribute(std::string const& attName, int data);
     void setAttribute(std::string const& attName, double data);
     void setAttribute(std::string const& attName, std::string const& data);

     // Return false if attribute with the given data type does not exist.
     bool getAttribute(std::string const& attName, int& data);
     bool getAttribute(std::string const& attName, double& data);
     bool getAttribute(std::string const& attName, std::string& data);

     BaseEntity* makeCopy() const = 0;
     virtual std::ostream& write(std::ostream& out) const = 0;
     virtual std::istream& read(std::istream& in) const = 0;

Some of the leaf level types are Part, Assembly, Face, Edge, Vertex.

Part and Assembly usually have a base class. An Assembly is conceptually a composite Part. Hence, they have a lot of common functionality that can be captured in an intermediate base class, such as Model.

class Model : public BaseEntity

    void setParent(Model* model);
    Model* getParent() const;

    // Assume there is a type called Transform
    Transform getTransformToParent() const;

    // More convenience functions to position a Part/Assembly
    // in the parent Model.
    // ...

    virtual double getVolume() const = 0;
    virtual double getSurfaceArea() const = 0;

    // More query functions common to Part and Assembly
    // ...

Face, Edge, and Vertex are topological entities of the BREP model. The common functoinality of these classes can be captured in an intermediate clas, such as TopologyEntity.

class TopologyEntity : public BaseEntity

    void setID(int id);
    int getID() const;

    void setPart(Part* part);
    Part* getPart() const;

    // More convenience functions for all derived classes.
    // ...


Neither Model nor TopologyEntity are concrete classes. They define abstractions that make sense. They may implement common functionality. They may add more virtual functions that the concrete classes must implement.

Here's a diagram of such a class hierarchy.

enter image description here

  • 3
    You may be correct, but this answer could use some more support. Unless it is true that large, 20 year old applications never contain bad design.
    – user82096
    Apr 19, 2017 at 15:21
  • @dan1111, of course.
    – R Sahu
    Apr 19, 2017 at 16:12

Not the answer you're looking for? Browse other questions tagged or ask your own question.