Main Content

MISRA C++:2023 Rule 15.1.2

All constructors of a class should explicitly initialize all of its virtual base classes and immediate base classes

Since R2024b

Description

Rule Definition

All constructors of a class should explicitly initialize all of its virtual base classes and immediate base classes.

Rationale

Class inheritance hierarchies can be complex and can introduce confusion around which constructors are called and in what order. If a class has immediate and virtual base classes, the user-provided constructors of the derived class that are not defaulted should explicitly initialize the base classes to clarify which constructor is used and with what parameters.

This rule does not apply to empty classes where there is nothing to initialize. A class is empty if all of these are true:

  • The class has no nonstatic data members.

  • The class has no virtual member functions.

  • The class has no virtual base classes.

  • The class has only empty base classes.

Polyspace Implementation

The coding rule checker reports a violation if the constructor of a derived class does not explicitly initialize all nonempty immediate base classes and virtual base classes using member initialization list or by delegating to a compliant constructor.

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

In this example, classes RetiredMember and ActiveRoster inherit from classes Player and Coach, which in turn both inherit from the virtual base class ClubMember.

Polyspace reports a violation on the constructor of the class RetiredMember because it does not explicitly initialize immediate base classes Player and Coach. The noninitialization of the immediate base classes makes it unclear which constructor of ClubMember is preferred.

In the case of the class ActiveRoster, the constructor is compliant because it initializes both of its base classes, Player and Coach, and its virtual base class, ClubMember. The initialization makes it clear which constructors are called and with what parameters.

#include <iostream>
#include <string>

class ClubMember
{
public:
    ClubMember()
    {
        // Default constructor
    }

    ClubMember(const std::string &name)
    {
        // Parameterized constructor
    }
    ClubMember(const int &jerseyNumber)
    {
        // Parameterized constructor
    }
};

class Player : virtual public ClubMember
{
public:
    Player() : ClubMember("Player Name")
    {
        // Default constructor
    }
    Player(const int &jerseyNumber) : ClubMember(jerseyNumber)
    {
        // Default constructor
    }
};

class Coach : virtual public ClubMember
{
public:
    Coach() : ClubMember("Coach Name")
    {
        // Default constructor
    }
};

class RetiredMember : public Player, public Coach
{
public:
    RetiredMember()                                     // Noncompliant 
    {
        // Default constructor
    }
};

class ActiveRoster : public Player, public Coach
{
public:
    ActiveRoster() : ClubMember(), Coach(), Player(25)  // Compliant
    {
        // Default constructor
    }
};

In this example, the class Derived derives from the aggregate base class Base. The constructor of the derived class initializes the data members of the base in the function body. Polyspace reports a violation.

#include <iostream>

// Base class (aggregate)
class Base {
public:
    int a;
    double b;
    char c;
};

// Derived class
class Derived : public Base {
public:
    // Constructor of Derived class
    Derived(int aVal, double bVal, char cVal) { //Noncompliant
        // Explicitly initializing base class members
        a = aVal;
        b = bVal;
        c = cVal;
    }

    // Member function to display the values
    void display() const {
        std::cout << "a: " << a << ", b: " << b << ", c: " << c << std::endl;
    }

    // Additional member functions can be added here
    void increment() {
        ++a;
        b += 1.0;
        ++c;
    }
};

Correction — Use Member Initialization List

To fix this violations, initialize the aggregate Base by using member initialization list in the constructor of Derived.

#include <iostream>

// Base class (aggregate)
class Base {
public:
	int a;
	double b;
	char c;
};

// Derived class
class Derived : public Base {
public:
	// Constructor of Derived class
	Derived(int aVal, double bVal, char cVal)
		: Base{aVal, bVal, cVal} { //Compliant
	}

	// Member function to display the values
	void display() const {
		std::cout << "a: " << a << ", b: " << b << ", c: " << c << std::endl;
	}

	// Additional member functions can be added here
	void increment() {
		++a;
		b += 1.0;
		++c;
	}
};

Check Information

Group: Special member functions
Category: Advisory

Version History

Introduced in R2024b