Question

C++ Base Class Constructor Rules Explained

cppinheritanceconstructor

Question

In C++, what are the rules for calling a base class constructor from a derived class?

For example, in Java, the base constructor must be called as the first line of the subclass constructor. If you do not call it explicitly, Java inserts an implicit call to the no-argument super() constructor, which causes a compile error if that constructor does not exist.

How does this work in C++?

Short Answer

By the end of this page, you will understand how C++ constructs base classes from derived classes, when a base constructor is called automatically, how to explicitly choose which base constructor to call, and what order constructors run in. You will also see common mistakes and how this differs from Java.

Concept

In C++, a derived object is built in layers.

When you create an object of a derived class, C++ first constructs its base class subobject, then constructs the derived class's own members and body. This happens automatically as part of object construction.

The important rule is:

  • Base class constructors are called before the derived class constructor body runs.
  • You do not call the base constructor inside the body like a normal function.
  • Instead, you choose the base constructor in the derived constructor's member initializer list.

Basic idea

class Base {
public:
    Base(int x) {}
};

class Derived : public Base {
public:
    Derived(int x) : Base(x) {}
};

Here, Base(x) is not a normal function call. It tells C++ which Base constructor should be used before Derived is finished being constructed.

If you do not specify a base constructor

If the derived constructor does not mention the base class in the initializer list, C++ tries to call the base class's default constructor.

class Base {
public:
    Base() {}
};

class Derived : public Base {
public:
    Derived() {}
};

This works because Base() exists.

But if the base class has no default constructor, the code fails:

class Base {
public:
    Base(int x) {}
};

class Derived : public Base {
public:
    Derived() {}
};

This is an error because C++ tries to call Base() automatically, but Base() does not exist.

Why this matters

This rule matters because construction is about guaranteeing that every part of an object is valid before you use it. A derived class depends on its base class already being properly initialized. That is why C++ forces base construction to happen first.

This also affects:

  • classes with constructor parameters
  • classes with const members or reference members
  • inheritance hierarchies in real applications
  • resource management patterns such as RAII

Mental Model

Think of a derived object like building a house on top of a foundation.

  • The base class is the foundation.
  • The derived class is the upper structure.

You cannot build the upper floor first and then decide what kind of foundation you wanted. The foundation must be poured first.

In C++, the member initializer list is where you tell the builder which foundation to use.

Derived(int x) : Base(x) {}

That means: "Before building the Derived part, first construct the Base part with x."

The constructor body runs only after that foundation already exists.

Take Quiz

Syntax and Examples

Core syntax

Use the base class constructor in the derived constructor's initializer list:

class Base {
public:
    Base(int value) {}
};

class Derived : public Base {
public:
    Derived(int value) : Base(value) {}
};

Example 1: Explicitly calling a base constructor

#include <iostream>
using namespace std;

class Animal {
public:
    Animal(string name) {
        cout << "Animal constructed: " << name << endl;
    }
};

class Dog : public Animal {
public:
    Dog(string name) : Animal(name) {
        cout << "Dog constructed" << endl;
    }
};

int main() {
    Dog d("Rex");
}

What this does

  • Dog("Rex") starts constructing a Dog object.
  • Before Dog's constructor body runs, Animal(name) runs.
  • After the base class is ready, the Dog constructor body runs.

Output

Animal constructed: Rex
Dog constructed

Example 2: Default base constructor used automatically

#include <iostream>
using namespace std;

class Base {
public:
    Base() {
        cout << "Base default constructor" << endl;
    }
};

class Derived : public Base {
public:
    Derived() {
        cout << "Derived constructor" << endl;
    }
};

int main() {
    Derived d;
}

Output

Base default constructor
Derived constructor

Because Derived() does not specify a base constructor, C++ uses Base() automatically.

Example 3: Compile error when no default base constructor exists

class Base {
public:
    Base(int x) {}
};

class Derived : public Base {
public:
    Derived() {}
};

This fails because C++ tries to call Base() automatically, but only Base(int) exists.

Step by Step Execution

Consider this example:

#include <iostream>
using namespace std;

class Base {
public:
    Base(int x) {
        cout << "Base: " << x << endl;
    }
};

class Derived : public Base {
public:
    Derived(int x, int y) : Base(x) {
        cout << "Derived: " << y << endl;
    }
};

int main() {
    Derived obj(10, 20);
}

Step-by-step

  1. main() creates obj with Derived obj(10, 20);
  2. C++ starts constructing a Derived object.
  3. Before entering the Derived constructor body, it sees : Base(x) in the initializer list.
  4. Base(10) runs first.
  5. It prints:
Base: 10
  1. Now the base part of the object is fully constructed.
  2. C++ enters the Derived constructor body.
  3. It prints:
Derived: 20

Final output

Base: 10
Derived: 20

Key takeaway

Even though the Derived constructor appears in your code, the base constructor always runs first. The initializer list selects the base constructor, and the body runs afterward.

Real World Use Cases

Base constructor calls appear often in real C++ programs.

1. Initializing shared state in a framework base class

A base class may store common data such as an ID, name, file path, or configuration.

class Widget {
public:
    Widget(string id) {}
};

class Button : public Widget {
public:
    Button(string id) : Widget(id) {}
};

2. Resource management

A base class may open or manage a resource during construction.

class FileOwner {
public:
    FileOwner(const string& path) {}
};

class LogFile : public FileOwner {
public:
    LogFile(const string& path) : FileOwner(path) {}
};

3. Reusing validation or setup logic

A base class can ensure core invariants are established before the derived class adds extra behavior.

4. GUI, game, and engine code

Frameworks often have base classes like Entity, Component, or Window. Derived classes pass values up to the base constructor so the framework can initialize common behavior first.

5. API and server code

Controllers, handlers, or service classes may inherit from a base type that stores dependencies, environment settings, or shared metadata.

Take Quiz

Real Codebase Usage

In real codebases, developers usually combine base constructor calls with a few common patterns.

Guarding object validity early

The base class often establishes state that every derived object must have.

class Connection {
public:
    Connection(string host) {
        // validate or store host
    }
};

class SecureConnection : public Connection {
public:
    SecureConnection(string host) : Connection(host) {}
};

Forwarding constructor arguments

A common pattern is to receive arguments in the derived constructor and pass some or all of them to the base constructor.

class Person {
public:
    Person(string name) {}
};

class Employee : public Person {
public:
    Employee(string name, int id) : Person(name), employeeId(id) {}

private:
    int employeeId;
};

Initializing members and base classes together

Initializer lists are used not just for base classes, but also for members.

class Base {
public:
    Base(int x) {}
};

class Derived : public Base {
public:
    Derived(int x, int y) : Base(x), value(y) {}

private:
    int value;
};

Constructor delegation is different

You cannot initialize a base class later from inside the constructor body. It must happen during construction.

Error handling

If base construction fails by throwing an exception, the derived constructor body never runs. This is important in code that manages files, sockets, memory, or locks.

Common Mistakes

1. Trying to call the base constructor inside the constructor body

This is wrong:

class Base {
public:
    Base(int x) {}
};

class Derived : public Base {
public:
    Derived(int x) {
        Base(x); // does not initialize the base subobject
    }
};

Why it is wrong:

  • The base subobject has already been constructed before the body starts.
  • Base(x); inside the body creates a temporary object instead of initializing the inherited base part.

Correct version:

class Derived : public Base {
public:
    Derived(int x) : Base(x) {}
};

2. Forgetting that C++ uses the default base constructor automatically

Broken code:

class Base {
public:
    Base(int x) {}
};

class Derived : public Base {
public:
    Derived() {}
};

Problem:

  • C++ tries Base() automatically.
  • But Base() does not exist.

Fix:

class Derived : public Base {
public:
    Derived() : Base(0) {}
};

3. Assuming initializer list order controls construction order

class Base1 {
public:
    Base1() {}
};

class Base2 {
public:
    Base2() {}
};

class Derived : public Base1, public Base2 {
public:
    Derived() : Base2(), Base1() {}
};

Many beginners think Base2 will be constructed first because it appears first in the initializer list. That is false.

Construction order follows the class declaration order:

class Derived : public Base1, public Base2

So Base1 is constructed before Base2.

4. Forgetting member initialization also happens before the body

Members, like base classes, should usually be initialized in the initializer list rather than assigned in the body.

5. Expecting Java-style syntax

In Java, super(...) appears in the constructor. In C++, the equivalent is the initializer list syntax:

Derived(int x) : Base(x) {}

Comparisons

C++ vs Java base constructor rules

TopicC++Java
Where base constructor is specifiedIn the initializer listIn the constructor using super(...)
Must base construction happen before derived body?YesYes
Automatic call if omittedYes, tries the base default constructorYes, inserts super()
Error if no default constructor existsYesYes
Can you call base constructor in body?NoNo
Syntax styleDerived() : Base(args) {}Derived() { super(args); }

Initializer list vs constructor body

ApproachUse caseImportant note
Initializer listInitialize base classes and membersRuns before constructor body
Constructor bodyAdditional logic after initializationToo late for base construction

Explicit base constructor vs implicit default constructor

SituationResult
Derived() : Base(5) {}Calls Base(int)
Derived() {} and Base() existsCalls Base() automatically
Derived() {} and Base() does not existCompile error
Take Quiz

Cheat Sheet

Quick rules

  • A base class is constructed before the derived class body runs.
  • Use the initializer list to choose the base constructor.
  • Syntax:
Derived(args) : Base(baseArgs) {}
  • If you omit the base constructor, C++ tries to call the base default constructor.
  • If no default constructor exists, compilation fails.
  • You cannot initialize the base class from inside the constructor body.
  • Base classes are constructed before members.
  • With multiple base classes, construction order follows the inheritance declaration order, not the initializer list order.

Common pattern

class Base {
public:
    Base(int x) {}
};

class Derived : public Base {
public:
    Derived(int x, int y) : Base(x), value(y) {}

private:
    int value;
};

Wrong pattern

Derived(int x) {
    Base(x); // wrong: temporary object, not base initialization
}

Remember

  • Initialization happens first.
  • Constructor body happens second.

FAQ

What happens if I do not call the base class constructor in C++?

C++ automatically tries to call the base class default constructor. If the base class has no default constructor, compilation fails.

Can I call the base constructor from inside the derived constructor body?

No. By the time the body runs, the base part has already been constructed. You must use the initializer list.

Is Base(x) inside the initializer list a normal function call?

No. It is constructor initialization syntax, not a regular function call.

In what order are constructors called in inheritance?

Base class constructors run first, then member objects, then the derived constructor body.

What if there are multiple base classes?

They are constructed in the order they appear in the class inheritance declaration, not the order written in the initializer list.

Is C++ behavior similar to Java super()?

Yes in purpose, but the syntax is different. C++ uses the initializer list, while Java uses super(...) inside the constructor.

What if the base constructor throws an exception?

The derived constructor body will not run, because the object was not fully constructed.

Do I always need to write the base constructor explicitly?

No. Only when you want a specific base constructor or when the base has no usable default constructor.

Take Quiz

Mini Project

Description

Build a small inheritance example that models a user account system. The base class should store a username, and the derived class should add a permission level. This demonstrates how a derived class passes required data to the base constructor during object creation.

Goal

Create a derived object that correctly initializes both the base class and its own member data using a constructor initializer list.

Requirements

  • Create a base class named User with a constructor that requires a username.
  • Create a derived class named AdminUser that inherits from User.
  • Pass the username from AdminUser to the User constructor.
  • Store a permission level inside AdminUser.
  • Print both the username and permission level to confirm construction worked.
Take Quiz

Keep learning

Related questions

View more