Constructor / Destructor
In C++, a constructor is automatically called when an object is created, and a destructor is automatically called when the object is destroyed. Constructors handle member initialization while destructors handle cleanup such as releasing resources or logging. This page explains the member initializer list, constructor overloading, and basic destructor usage.
Syntax
// ========================================
// Constructor and destructor basic syntax
// ========================================
class ClassName {
public:
// Constructor (same name as the class, no return type)
ClassName(Args) {
// Initialization
}
// Constructor with member initializer list
ClassName(Type arg1, Type arg2)
: member1_(arg1), member2_(arg2) {
// Additional initialization
}
// Default constructor (no arguments)
ClassName() {
// Initialize with default values
}
// Overloaded constructor (different type/count of args)
ClassName(Type arg1) {
// Initialize with arg1 only
}
// Destructor (~ + class name, no arguments, no return type)
~ClassName() {
// Cleanup (release resources, etc.)
}
};
// ========================================
// Object destruction with delete
// ========================================
ClassName* ptr = new ClassName(args); // Constructor is called
delete ptr; // Destructor is called
Syntax Reference
| Syntax / Keyword | Description |
|---|---|
| ClassName(args) { } | Defines a constructor. Uses the same name as the class with no return type. Called automatically when the object is created. |
| : member_(arg) | Member initializer list. Written after the argument list with a colon. Initializes members directly rather than via assignment, which is the only way to initialize const members and reference members. |
| ClassName() { } | Default constructor. Called when an object is created without arguments. The compiler generates one automatically if none is defined. |
| ClassName(Type arg) { } | Overloaded constructor. Multiple constructors can be defined with different argument types or counts. |
| ~ClassName() { } | Defines a destructor. The class name is prefixed with ~. No arguments or return type. Called automatically when the object is destroyed. |
| delete pointer | Releases a heap-allocated object created with new. The destructor is called at this point. |
Sample Code
kof_fighter.cpp
// ========================================
// kof_fighter.cpp — Constructor and destructor
// Demonstrates constructors and destructors
// using a Fighter class for KOF characters
// ========================================
#include <iostream>
#include <string>
class Fighter {
private:
std::string name_;
std::string team_;
int hp_;
public:
// Overloaded constructor (all arguments)
Fighter(const std::string& name, const std::string& team, int hp)
: name_(name), team_(team), hp_(hp) {
std::cout << "[Created] " << name_ << " has joined." << std::endl;
}
// Overloaded constructor (name only, default hp = 100)
Fighter(const std::string& name)
: name_(name), team_("Free"), hp_(100) {
std::cout << "[Created] " << name_ << " joined as a free fighter." << std::endl;
}
// Default constructor (no arguments)
Fighter()
: name_("Unknown"), team_("Unaffiliated"), hp_(0) {
std::cout << "[Created] An unnamed fighter was created." << std::endl;
}
// Destructor
~Fighter() {
std::cout << "[Destroyed] " << name_ << " has left." << std::endl;
}
void showInfo() const {
std::cout << "Name: " << name_ << " / Team: " << team_
<< " / HP: " << hp_ << std::endl;
}
void takeDamage(int dmg) {
hp_ -= dmg;
if (hp_ < 0) hp_ = 0;
std::cout << name_ << " took " << dmg << " damage. HP remaining: " << hp_ << std::endl;
}
};
int main() {
std::cout << "=== Stack objects ===" << std::endl;
Fighter kyo("Kusanagi Kyo", "Japan Team", 200);
Fighter iori("Yagami Iori", "Yagami Team", 195);
Fighter ash("Ash Crimson");
Fighter unknown;
std::cout << std::endl;
std::cout << "=== Fighter info ===" << std::endl;
kyo.showInfo();
iori.showInfo();
ash.showInfo();
unknown.showInfo();
std::cout << std::endl;
std::cout << "=== Battle start ===" << std::endl;
kyo.takeDamage(80);
iori.takeDamage(60);
std::cout << std::endl;
std::cout << "=== Heap object ===" << std::endl;
Fighter* leona = new Fighter("Leona Heidern", "Ikari Team", 185);
leona->showInfo();
leona->takeDamage(50);
std::cout << std::endl;
std::cout << "=== delete (destructor called) ===" << std::endl;
delete leona;
std::cout << std::endl;
std::cout << "=== End of main (stack objects destroyed in reverse order) ===" << std::endl;
return 0;
}
g++ -std=c++17 kof_fighter.cpp -o kof_fighter ./kof_fighter === Stack objects === [Created] Kusanagi Kyo has joined. [Created] Yagami Iori has joined. [Created] Ash Crimson joined as a free fighter. [Created] An unnamed fighter was created. === Fighter info === Name: Kusanagi Kyo / Team: Japan Team / HP: 200 Name: Yagami Iori / Team: Yagami Team / HP: 195 Name: Ash Crimson / Team: Free / HP: 100 Name: Unknown / Team: Unaffiliated / HP: 0 === Battle start === Kusanagi Kyo took 80 damage. HP remaining: 120 Yagami Iori took 60 damage. HP remaining: 135 === Heap object === [Created] Leona Heidern has joined. Name: Leona Heidern / Team: Ikari Team / HP: 185 Leona Heidern took 50 damage. HP remaining: 135 === delete (destructor called) === [Destroyed] Leona Heidern has left. === End of main (stack objects destroyed in reverse order) === [Destroyed] Unknown has left. [Destroyed] Ash Crimson has left. [Destroyed] Yagami Iori has left. [Destroyed] Kusanagi Kyo has left.
Common Mistake 1: Forgetting to make the base class destructor virtual
If the base class destructor is not virtual, deleting a derived class object through a base class pointer only calls the base destructor, causing the derived class destructor to be skipped and resources to leak.
// NG: Non-virtual base destructor
class Base {
public:
~Base() { /* base cleanup */ }
};
class Derived : public Base {
public:
~Derived() { /* derived cleanup — never called! */ }
};
Base* p = new Derived();
delete p; // Only Base::~Base() is called
OK: Mark the base class destructor as virtual.
// OK: virtual destructor in base class
class Base {
public:
virtual ~Base() { /* base cleanup */ }
};
class Derived : public Base {
public:
~Derived() override { /* called correctly */ }
};
Base* p = new Derived();
delete p; // Derived::~Derived() → Base::~Base() called in order
g++ -std=c++17 virtual_dtor.cpp -o virtual_dtor ./virtual_dtor [Derived destructor] cleanup done [Base destructor] cleanup done
Common Mistake 2: Assigning to a const member in the constructor body
const members and reference members cannot be initialized via assignment in the constructor body. The member initializer list must be used.
// NG: Assigning a const member in the constructor body
class Fighter {
const std::string name_;
public:
Fighter(const std::string& n) {
name_ = n; // Compile error: const member cannot be assigned
}
};
OK: Use the member initializer list.
// OK: Initialize via member initializer list
class Fighter {
const std::string name_;
public:
Fighter(const std::string& n)
: name_(n) {} // const members can be initialized this way
};
g++ -std=c++17 init_list.cpp -o init_list ./init_list Fighter: Iori
Overview
A constructor shares the same name as its class and has no return type. It is called automatically immediately after the object is created and is responsible for initializing member variables. The member initializer list (: member_(arg)) is more efficient than assignment in the constructor body, and it is the only way to initialize const members and reference members. Constructors can be overloaded, allowing multiple definitions with different argument types or counts for flexible object creation. The destructor has the class name prefixed with ~ and takes no arguments or return type. Stack objects have their destructors called automatically when they go out of scope, in the reverse order of construction. For heap-allocated objects created with new, the destructor is not called automatically, so delete must be called explicitly, or smart pointers such as std::unique_ptr can be used instead.
If you find any errors or copyright issues, please contact us.