- References
- Function Overloading
- Default Function Arguments
- Inline Function
- Dynamic Memory Allocation
- Placement New
- nullptr
- Namespaces
- Type Aliases
- Enum classes
- constexpr
- static_assert
- mutable Keyword
- auto Keyword
- Smart Pointers
- Basics of Classes
- Constructors
- Destructors
- Operator Overloading
- Copy Semantics
- Move Semantics
- Composition, RAII & Ownership
- Inheritance
- Polymorphism
- Abstraction
- Encapsulation
- Template
- Static Memory
- Friend Function
- this Pointer
- Function Pointer
- Lambdas and Callback Management
- Union
Constructors (Automatic Initialization)

A Constructor is a special member function that runs automatically when an object is created. Its purpose is to guarantee that the object starts in a valid state (e.g., pointers assigned, hardware initialized, invariants checked) before any other code uses it.
It has no return type and shares the same name as the class.
Syntax & Usage
1. Basic & Parameterized Constructors
The most common forms used to initialize variables.
class GPIO {
int pin;
public:
// 1. Default Constructor (No args)
GPIO() { pin = 0; }
// 2. Parameterized Constructor (With args)
GPIO(int p) { pin = p; }
};
GPIO led; // Calls GPIO()
GPIO motor(9); // Calls GPIO(int)2. Member Initializer Lists (Crucial for Efficiency)
Initializes variables before the constructor body runs. This is mandatory for const members and References, and avoids "double-writing" variables.
class Sensor {
const int id;
int& bus_ref;
public:
// Syntax: : member(value), member(value)
Sensor(int i, int& bus) : id(i), bus_ref(bus) {
// Body is empty; work is already done.
}
};3. Advanced Variants (explicit, Copy, delete)
These control how objects are created or copied, preventing dangerous bugs.
explicit: Prevents accidental implicit conversions (e.g., passingintwhere aDriverobject is expected).- Copy Constructor: Defines how to clone an object (crucial for Deep Copies of pointers).
= delete: Disables a constructor (used for Singletons or unique hardware drivers).
class Driver {
int* buffer;
public:
// PREVENT implicit conversion from int to Driver
explicit Driver(int size) { buffer = new int[size]; }
// CUSTOM Copy Constructor (Deep Copy)
Driver(const Driver& other) {
buffer = new int[10];
memcpy(buffer, other.buffer, 10 * sizeof(int));
}
// DISABLE Copying entirely (Common for hardware drivers)
// Driver(const Driver&) = delete;
};Initialization vs Assignment Flow
| Feature | Assignment (Inside Body) | Initializer List (: x(10)) |
|---|---|---|
| Mechanism | Variable created (default), then overwritten. | Variable created with value. |
| Performance | Slower (Two steps). | Faster (One step). |
| Constraints | Cannot init const or Reference. | Required for const/Reference. |
Relevance in Embedded/Firmware
1. Impossible-to-Forget Initialization
In C, forgetting UART_Init() crashes the system.
In C++, constructors force you to provide configuration (e.g., Baud Rate) at creation time. The object never exists in an uninitialized state.
2. RAII (Resource Acquisition Is Initialization)
The "Scope Lock" pattern: A constructor acquires a resource (disables interrupts, takes a mutex), and the Destructor releases it.
{
InterruptLock lock; // Constructor: __disable_irq();
// Critical Section
} // Destructor: __enable_irq(); automatic at end of scope.
3. Unique Hardware Access
Using = delete on copy constructors ensures you don't have two software objects trying to control the same physical UART peripheral, preventing race conditions.
Common Pitfalls (Practical Tips)
| Pitfall | Details |
|---|---|
| ❌ Heavy Work | Avoid complex hardware delays or checks in constructors for Global/Static objects. They run before main(), which can make the system appear to hang at boot. |
| ❌ Initializer Order | Members are initialized in the order they are declared in the class, NOT the order in the list.
|
| ❌ Implicit Conversion | Without explicit, void func(Driver d) can be called as func(100), silently creating a 100-byte driver. This is confusing and dangerous. |
| ✅ Default Constructor | If you define any constructor, the compiler removes the default (empty) one. You must explicitly add GPIO() = default; if you still need it. |
Concept understood? Let's apply and learn for real