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.
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 toTest()first, then adds count-specific work.Test(int, std::string)delegates toTest(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:
- It chooses the constructor
Test(int, const std::string&). - That constructor says
: Test(count), so C++ first runsTest(int). Test(int)says: Test(), so C++ first runsTest().Test()prints:
1. Default constructor
- Control returns to
Test(int), which prints:
2. Count constructor: 10
- 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.
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
| Concept | C# | C++ |
|---|---|---|
| Constructor chaining syntax | : this(...) | : ClassName(...) |
| Where chaining happens | Constructor initializer | Member initializer list |
| Can constructor be called in body to reinitialize same object? | No | No |
| Calling class name in constructor body | Not used for chaining | Creates a temporary object |
| Language support | Built in | Built in from C++11 |
Delegating constructor vs helper function
| Approach | Best for | Drawback |
|---|---|---|
| Delegating constructor | Reusing construction logic | Requires C++11+ |
| Private helper method | Sharing repeated code | Cannot replace true member initialization |
| Factory function | Complex creation logic | Extra function layer |
Initializer list vs assignment in constructor body
| Approach | Example | Preferred? |
|---|---|---|
| Initializer list | User() : age(0) {} | Yes |
| Assignment in body | User() { age = 0; } | Usually no |
Initializer lists are preferred because members are initialized directly rather than created first and assigned later.
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++.
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
DatabaseConfigclass withhost,port, anduseSslfields. - 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.
Keep learning
Related questions
Advantages of Brace Initialization in C++
Learn why C++ brace initialization is often clearer and safer than other object initialization styles, with examples and common pitfalls.
Basic Rules and Idioms for Operator Overloading in C++
Learn the core rules, syntax, and common idioms for operator overloading in C++, including member vs non-member operators.
C++ Aggregates, Trivial Types, Trivially Copyable Types, and PODs Explained
Learn what aggregates, trivial types, trivially copyable types, and PODs mean in C++, how they differ, and why they matter.