Main Content

AUTOSAR C++14 Rule A10-1-1

Class shall not be derived from more than one base class which is not an interface class

Since R2020a

Description

Rule Definition

Class shall not be derived from more than one base class which is not an interface class.

Rationale

If a class inherits from multiple non-interface classes, the class essentially has access to multiple implementations. Maintaining the code can be difficult.

When a class inherits from multiple non-interface classes, there is a likelihood that the same member function exists in those base classes and must be overridden in the derived class. The likelihood increases when those base classes themselves inherit from a common base class (diamond structure).

Suppose, an interface class Interface has two concrete implementations, Impl1 and Impl2, and a class Final derives from both implementations. The class hierarchy has this diamond structure.

A pictorial representation of the diamond hierarchy. Class 'Final' inherits from the classes 'Imp1' and 'Impl2', which themselves inherit from the class 'Interface'.

The following issues can occur:

  • Overrides required in final derived class for disambiguation:

    Both implementations Impl1 and Impl2 have a copy of all methods of the class Interface. To disambiguate which copy can be called through a Final object, you typically create yet another override of all methods in the Final class where you call both copies explicitly using the scope resolution operator :: (or one copy, if you choose). See example below.

    Each time you add a new pure virtual function to the class Interface, you have to not only create implementations in the immediate derived classes but also keep track of the entire class hierarchy and create overrides of those implementations in the class Final.

    If the original class Interface is not an interface class, the problem is even more acute. Unless the inheritances are virtual, two copies of the methods of Interface are implicitly made in Impl1 and Impl2 (the diamond problem).

  • Final derived class responsible for initializing all classes in hierarchy:

    To avoid double initializations in multiple inheritance, the C++ standard requires that you call the constructors of all previous classes in the most derived class.

    In the preceding example, the Final class constructor not only has to call the constructors of Impl1 and Impl2 but also the constructor of their parent class Interface. You have to trace beyond the immediate parents to determine which constructors to call in the final derived class.

These problems disappear if multiple inheritances are restricted to situations where a class can derive from multiple classes but only one of them can be a non-interface class. An interface class is a class that has only pure virtual functions and data members that are compile-time constants (static, contexpr-s). The class has no state and its sole purpose is to be implemented by derived classes.

Multiple inheritance was designed for situations where a class extends one concrete implementation but also implements other ideas represented by interface classes. Other uses of multiple inheritance can lead to maintenance hazards.

Polyspace Implementation

The checker flags multiple inheritances where more than one base class is a non-interface class.

An interface class is one that has only pure virtual functions and data members that are compile-time constants (static, contexpr-s). Any constructor or destructor is set to =default or =delete.

Troubleshooting

If you expect a rule violation but Polyspace® does not report it, see Diagnose Why Coding Standard Violations Do Not Appear as Expected.

Examples

expand all

class Interface {
    public:
    virtual void setVal()=0;
};

class Impl1: public Interface{
    int val1;
public:
    void setVal() {
        val1 = 0;
    }
};

class Impl2: public Interface{
    int val2;
public:
    void setVal() {
        val2 = 0;
    }
};

class Final: public Impl1, public Impl2 { //Noncompliant
public:
    void setVal() {
        Impl1::setVal();
        Impl2::setVal();
    } 
    
};

void main() {
    Final finalObj;
    finalObj.setVal();
}

In this example, the class final derives from classes Impl1 and Impl2. Both classes Impl1 and Impl2 have data members that are not compile-time constants and member functions that are not pure virtual functions. Therefore, the classes are non-interface classes. Inheriting from two non-interface classes causes a coding rule violation.

Check Information

Group: Derived classes
Category: Required, Automated

Version History

Introduced in R2020a