Question

Constructor Chaining in C++: How Delegating Constructors Work

cppconstructordelegates

Question

In C#, it is common to chain constructors so that one constructor reuses the work of another. For example:

class Test {
    public Test() {
        DoSomething();
    }

    public Test(int count) : this() {
        DoSomethingWithCount(count);
    }

    public Test(int count, string name) : this(count) {
        DoSomethingWithName(name);
    }
}

Is there an equivalent way to do this in C++?

I tried calling the class name directly and also tried using the this keyword inside a constructor, but neither approach worked.

Short Answer

By the end of this page, you will understand how constructor chaining works in C++, when it is supported, and how to share initialization logic safely. You will learn about delegating constructors, initializer lists, older workarounds used before modern C++, and common mistakes beginners make when trying to call one constructor from another.

Concept

In C++, constructor chaining is usually called delegating constructors.

A delegating constructor is a constructor that forwards construction to another constructor in the same class.

In modern C++ (C++11 and later), this is supported directly:

class Test {
public:
    Test() {
        DoSomething();
    }

    Test(int count) : Test() {
        DoSomethingWithCount(count);
    }

    Test(int count, const std::string& name) : Test(count) {
        DoSomethingWithName(name);
    }

private:
    void DoSomething() {}
    void DoSomethingWithCount(int) {}
    void DoSomethingWithName(const std::string&) {}
};

This is the C++ equivalent of C# constructor chaining.

Why this matters

Constructors often need to do shared setup:

  • initialize member variables
  • validate input
  • open resources
  • avoid duplicated code

Without constructor chaining, you may repeat the same logic in multiple constructors, which makes code harder to maintain.

Important C++ rule

In C++, an object is constructed once. You cannot create it and then "re-run" another constructor on the same object by calling a constructor like a normal method.

That is why code like this does not do constructor chaining:

class Test {
public:
    Test() {}

    Test(int count) {
        Test(); // creates a temporary object, not this object
    }
};

This creates a separate temporary object instead of initializing the current one.

Likewise, constructors are not ordinary member functions, so you cannot call them with this->Test().

Before C++11

Before delegating constructors were added, developers usually avoided duplication by moving shared logic into:

  • a private helper function
  • a common initialization method
  • a factory function

However, helper functions are not a perfect replacement for constructor delegation, because member initialization really should happen in the member initializer list when possible.

Mental Model

Think of constructing a C++ object like assembling a machine at a factory.

  • A constructor is the assembly process.
  • A delegating constructor says: "Start with the basic assembly process first, then add extra parts."
  • A failed attempt like calling Test() inside another constructor is like accidentally building a different machine on the side, not continuing work on the current one.

So in C++:

  • Test() : Test(other) means build this object by first using another constructor.
  • Test(); inside the constructor body means make a temporary separate object.

That difference is one of the most important ideas to remember.

Take Quiz

Syntax and Examples

Core syntax

In C++11 and later, you delegate to another constructor in the member initializer list:

ClassName(parameters) : ClassName(other_arguments) {
    // extra work here
}

Example

#include <iostream>
#include <string>

class Test {
public:
    Test() {
        std::cout << "Base setup\n";
    }

    Test(int count) : Test() {
        std::cout << "Count: " << count << "\n";
    }

    Test(int count, const std::string& name) : Test(count) {
        std::cout << "Name: " << name << "\n";
    }
};

int main() {
    Test a;
    std::cout << "---\n";
    Test b(3);
    std::cout << "---\n";
    Test c(5, "Alice");
}

Output

Base setup
---
Base setup
Count: 3
---
Base setup
Count: 5
Name: Alice

Why this works

  • Test() performs the common setup.
  • Test(int) delegates to Test() first, then adds count-specific work.
  • Test(int, std::string) delegates to Test(int) first, then adds name-specific work.

This gives you a clean chain of construction.

Pre-C++11 workaround

If delegating constructors are not available, move shared logic into a helper:

#include <string>

class Test {
public:
    Test() {
        init();
    }

    Test(int count) {
        init();
        DoSomethingWithCount(count);
    }

    Test(int count, const std::string& name) {
        init();
        DoSomethingWithCount(count);
        DoSomethingWithName(name);
    }

private:
    void init() {
        DoSomething();
    }

    void DoSomething() {}
    void DoSomethingWithCount(int) {}
    void DoSomethingWithName(const std::string&) {}
};

This reduces duplication, but it is less elegant than true delegation.

Step by Step Execution

Consider this example:

#include <iostream>
#include <string>

class Test {
public:
    Test() {
        std::cout << "1. Default constructor\n";
    }

    Test(int count) : Test() {
        std::cout << "2. Count constructor: " << count << "\n";
    }

    Test(int count, const std::string& name) : Test(count) {
        std::cout << "3. Name constructor: " << name << "\n";
    }
};

int main() {
    Test t(10, "Sam");
}

What happens?

When this line runs:

Test t(10, "Sam");

C++ follows these steps:

  1. It chooses the constructor Test(int, const std::string&).
  2. That constructor says : Test(count), so C++ first runs Test(int).
  3. Test(int) says : Test(), so C++ first runs Test().
  4. Test() prints:
1. Default constructor
  1. Control returns to Test(int), which prints:
2. Count constructor: 10
  1. Control returns to Test(int, const std::string&), which prints:
3. Name constructor: Sam

Final output

1. Default constructor
2. Count constructor: 10
3. Name constructor: Sam

The key idea is that construction happens from the delegated constructor outward.

Real World Use Cases

Constructor chaining is useful whenever objects have multiple ways to be created but still need common setup.

Common examples

Configuration objects

class Config {
public:
    Config() : host("localhost"), port(8080) {}
    Config(int p) : Config() { port = p; }

private:
    std::string host;
    int port;
};

Use case:

  • default development settings
  • allow overriding only one value

File or resource wrappers

A class might always need base validation or default state before opening a file with different options.

Logging classes

A logger may always initialize a default log level, while other constructors add file names, prefixes, or formatting options.

API clients

An HTTP client may start with default headers and timeout values, while additional constructors supply a token, base URL, or retry settings.

Game objects or UI components

Objects may always need default position, ID, or style settings, while overloaded constructors customize size, label, or behavior.

Take Quiz

Real Codebase Usage

In real projects, developers use constructor chaining to keep initialization consistent and avoid copy-paste logic.

Common patterns

1. Default values plus overrides

A base constructor sets safe defaults, and other constructors override only what changes.

class ServerOptions {
public:
    ServerOptions() : port(80), useSsl(false) {}
    ServerOptions(int p) : ServerOptions() { port = p; }
    ServerOptions(int p, bool ssl) : ServerOptions(p) { useSsl = ssl; }

private:
    int port;
    bool useSsl;
};

2. Input validation in one place

One constructor can normalize or validate values before shared state is used.

3. Guarding against duplication

Instead of repeating the same setup in several constructors, delegate to a single constructor that owns the common initialization.

4. Combining with initializer lists

In C++, member initialization should usually happen in initializer lists, not by assigning inside the constructor body.

class User {
public:
    User() : name("Guest"), age(0) {}
    User(const std::string& n) : User() { name = n; }

private:
    std::string name;
    int age;
};

This is valid, but if possible, design the target constructor to initialize members directly.

5. Error handling

If construction can fail, many C++ codebases throw exceptions from constructors or move creation logic into factory functions. Constructor chaining helps centralize setup before failure points occur.

Good practice

Prefer one constructor to do the main initialization work, and let others delegate to it.

Common Mistakes

1. Calling the constructor like a normal function

Broken example:

class Test {
public:
    Test() {}

    Test(int count) {
        Test(); // wrong
    }
};

Problem

This creates a temporary Test object. It does not initialize the current object.

Fix

Use delegation in the initializer list:

class Test {
public:
    Test() {}
    Test(int count) : Test() {}
};

2. Trying to use this() like in C#

Broken example:

class Test {
public:
    Test() {}

    Test(int count) : this() { // wrong
    }
};

Problem

C++ does not use this() for constructor delegation.

Fix

Use the class name:

Test(int count) : Test() {}

3. Delegating in a cycle

Broken example:

class Test {
public:
    Test() : Test(0) {}
    Test(int x) : Test() {}
};

Problem

This creates infinite recursive delegation, which is not allowed.

Fix

Make sure one constructor is the final base constructor.

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

4. Assigning instead of initializing when avoidable

Less ideal:

class Item {
public:
    Item() {}
    Item(int id) : Item() {
        this->id = id;
    }

private:
    int id;
};

Problem

The member may be default-initialized first and assigned later.

Better approach

Initialize in the constructor that owns the real state:

class Item {
public:
    Item() : Item(0) {}
    Item(int idValue) : id(idValue) {}

private:
    int id;
};

5. Forgetting C++ version support

Delegating constructors require C++11 or later.

If you are using an older compiler standard, use a helper function instead.

Comparisons

ConceptC#C++
Constructor chaining syntax: this(...): ClassName(...)
Where chaining happensConstructor initializerMember initializer list
Can constructor be called in body to reinitialize same object?NoNo
Calling class name in constructor bodyNot used for chainingCreates a temporary object
Language supportBuilt inBuilt in from C++11

Delegating constructor vs helper function

ApproachBest forDrawback
Delegating constructorReusing construction logicRequires C++11+
Private helper methodSharing repeated codeCannot replace true member initialization
Factory functionComplex creation logicExtra function layer

Initializer list vs assignment in constructor body

ApproachExamplePreferred?
Initializer listUser() : age(0) {}Yes
Assignment in bodyUser() { age = 0; }Usually no

Initializer lists are preferred because members are initialized directly rather than created first and assigned later.

Take Quiz

Cheat Sheet

Constructor chaining in C++

Modern syntax

class Test {
public:
    Test() {}
    Test(int x) : Test() {}
    Test(int x, const std::string& name) : Test(x) {}
};

Rules

  • Use : ClassName(...) to delegate.
  • Delegation happens in the initializer list.
  • Only one constructor runs first as the target.
  • Add extra work in the constructor body after delegation.
  • Requires C++11 or later.

Do not do this

Test() ;          // declaration, not chaining
Test();           // creates a temporary object in a constructor body
this->Test();     // invalid
:this();          // C# style, not C++

Best practices

  • Put common setup in one constructor.
  • Prefer initializer lists for member initialization.
  • Avoid duplicated constructor logic.
  • Avoid cyclic delegation.

Pre-C++11 fallback

class Test {
public:
    Test() { init(); }
    Test(int x) { init(); }

private:
    void init() {}
};

FAQ

Can I call one constructor from another in C++?

Yes, in C++11 and later you can use delegating constructors with the syntax : ClassName(...).

Why does calling Test() inside a constructor not work?

Because it creates a separate temporary object instead of reusing the current object.

Is this() valid in C++ like it is in C#?

No. C++ constructor delegation uses the class name, not this().

Do delegating constructors work in old C++ versions?

No. They were added in C++11. In older code, use a helper function or redesign the constructors.

Should I use a helper function instead of constructor chaining?

Use a helper function only when delegating constructors are unavailable or when the shared code is not true initialization logic.

Can constructor delegation be recursive?

No. Cyclic delegation is invalid and must be avoided.

Should I initialize members in the body or the initializer list?

Prefer the initializer list whenever possible. It is usually more efficient and idiomatic in C++.

Take Quiz

Mini Project

Description

Build a small DatabaseConfig class that supports several ways of creating configuration objects while sharing common setup. This demonstrates constructor chaining in a realistic scenario: default values, partial customization, and full customization.

Goal

Create a class that provides sensible defaults and allows more specific constructors to reuse earlier initialization logic.

Requirements

  • Create a DatabaseConfig class with host, port, and useSsl fields.
  • Provide a default constructor that sets sensible default values.
  • Provide a constructor that changes only the port.
  • Provide a constructor that changes both host and port.
  • Provide a constructor that changes host, port, and SSL setting using constructor delegation.
Take Quiz

Keep learning

Related questions

View more