C++98corebeginner
Constructors
C++98 · The Foundation · Compiler flag: -std=c++98
Explanation
Special functions called during object creation to initialize data.
Real-World Scenario
Initialize a bank account with a starting balance.
Quick Snippet
snippet.cpp
class Account { public: Account(int bal) {} };Full Example
constructors.cpp
// CodeNebula - C++98 Example: Constructors
// Compile: g++ -std=c++98 -Wall -Wextra -o example constructors.cpp
// Demonstrates constructors in C++98: default constructors, parameterized
// constructors, overloaded constructors, copy constructors, member initializer
// lists, constructor delegation patterns, and destructor basics.
#include <iostream>
#include <cstring>
#include <cmath>
// ------------------------------------------------------------------
// 1. Class with default, parameterized, and overloaded constructors
// ------------------------------------------------------------------
class Point {
private:
double x_;
double y_;
public:
// Default constructor - no parameters
Point() : x_(0.0), y_(0.0)
{
std::cout << " Point() default constructor -> ("
<< x_ << ", " << y_ << ")" << std::endl;
}
// Parameterized constructor - two parameters
Point(double x, double y) : x_(x), y_(y)
{
std::cout << " Point(" << x << ", " << y
<< ") parameterized constructor" << std::endl;
}
// Overloaded constructor - single value for both x and y
Point(double val) : x_(val), y_(val)
{
std::cout << " Point(" << val
<< ") single-value constructor" << std::endl;
}
// Copy constructor
Point(const Point& other) : x_(other.x_), y_(other.y_)
{
std::cout << " Point(copy) copy constructor -> ("
<< x_ << ", " << y_ << ")" << std::endl;
}
double getX() const { return x_; }
double getY() const { return y_; }
void print() const
{
std::cout << "(" << x_ << ", " << y_ << ")";
}
};
// ------------------------------------------------------------------
// 2. Class showing constructor with member initializer list importance
// ------------------------------------------------------------------
class Student {
private:
char name_[50];
int age_;
double gpa_;
const int id_; // const member MUST be initialized in init list
int& gradeRef_; // reference member MUST be initialized in init list
static int nextId_;
public:
// Constructor using member initializer list
// const and reference members can ONLY be initialized here, not in the body
Student(const char* name, int age, double gpa, int& gradeStorage)
: age_(age),
gpa_(gpa),
id_(nextId_++),
gradeRef_(gradeStorage)
{
std::strncpy(name_, name, 49);
name_[49] = '\0';
}
void print() const
{
std::cout << " ID:" << id_ << " " << name_
<< " Age:" << age_ << " GPA:" << gpa_ << std::endl;
}
};
int Student::nextId_ = 1001;
// ------------------------------------------------------------------
// 3. Class demonstrating constructor/destructor lifecycle
// ------------------------------------------------------------------
class LifecycleDemo {
private:
char label_[20];
public:
LifecycleDemo(const char* label)
{
std::strncpy(label_, label, 19);
label_[19] = '\0';
std::cout << " [CONSTRUCT] " << label_ << std::endl;
}
// Copy constructor
LifecycleDemo(const LifecycleDemo& other)
{
std::strncpy(label_, other.label_, 19);
label_[19] = '\0';
std::strncat(label_, "(cpy)", 19 - std::strlen(label_));
std::cout << " [COPY] " << label_ << std::endl;
}
~LifecycleDemo()
{
std::cout << " [DESTROY] " << label_ << std::endl;
}
};
// ------------------------------------------------------------------
// 4. Class with resource management (dynamic memory)
// ------------------------------------------------------------------
class DynamicArray {
private:
int* data_;
int size_;
int capacity_;
public:
// Default constructor
DynamicArray() : data_(new int[4]), size_(0), capacity_(4)
{
std::cout << " DynamicArray() - capacity 4" << std::endl;
}
// Parameterized constructor
DynamicArray(int capacity) : data_(new int[capacity]), size_(0), capacity_(capacity)
{
std::cout << " DynamicArray(" << capacity << ")" << std::endl;
}
// Constructor with initial values
DynamicArray(const int arr[], int count)
: data_(new int[count]), size_(count), capacity_(count)
{
for (int i = 0; i < count; ++i) {
data_[i] = arr[i];
}
std::cout << " DynamicArray(array, " << count << ")" << std::endl;
}
// Copy constructor (deep copy)
DynamicArray(const DynamicArray& other)
: data_(new int[other.capacity_]),
size_(other.size_),
capacity_(other.capacity_)
{
for (int i = 0; i < size_; ++i) {
data_[i] = other.data_[i];
}
std::cout << " DynamicArray(copy) - deep copy" << std::endl;
}
// Destructor - frees dynamic memory
~DynamicArray()
{
std::cout << " ~DynamicArray() - freeing "
<< capacity_ << " ints" << std::endl;
delete[] data_;
}
void push(int value)
{
if (size_ < capacity_) {
data_[size_++] = value;
}
}
void print() const
{
std::cout << "[";
for (int i = 0; i < size_; ++i) {
if (i > 0) std::cout << ", ";
std::cout << data_[i];
}
std::cout << "] (size=" << size_ << ", cap=" << capacity_ << ")";
}
};
// ------------------------------------------------------------------
// 5. Class with many constructor overloads (Rectangle)
// ------------------------------------------------------------------
class Rectangle {
private:
double x_, y_; // position
double width_, height_;
char name_[20];
public:
// Default: unit square at origin
Rectangle()
: x_(0), y_(0), width_(1), height_(1)
{
std::strcpy(name_, "default");
}
// Square at origin
Rectangle(double side)
: x_(0), y_(0), width_(side), height_(side)
{
std::strcpy(name_, "square");
}
// Rectangle at origin
Rectangle(double w, double h)
: x_(0), y_(0), width_(w), height_(h)
{
std::strcpy(name_, "rect");
}
// Rectangle at specified position
Rectangle(double x, double y, double w, double h)
: x_(x), y_(y), width_(w), height_(h)
{
std::strcpy(name_, "positioned");
}
// Named rectangle at position
Rectangle(const char* name, double x, double y, double w, double h)
: x_(x), y_(y), width_(w), height_(h)
{
std::strncpy(name_, name, 19);
name_[19] = '\0';
}
void print() const
{
std::cout << " " << name_ << ": pos(" << x_ << "," << y_
<< ") size(" << width_ << "x" << height_
<< ") area=" << width_ * height_ << std::endl;
}
};
// ------------------------------------------------------------------
// 6. Class demonstrating order of initialization
// ------------------------------------------------------------------
class InitOrder {
private:
int a_;
int b_;
int c_;
public:
// Members are initialized in DECLARATION ORDER, not init-list order!
// Here a_ is initialized first, then b_, then c_, regardless of
// the order they appear in the initializer list.
InitOrder(int val)
: c_(val * 3), // initialized THIRD (declared third)
a_(val), // initialized FIRST (declared first)
b_(val * 2) // initialized SECOND (declared second)
{
std::cout << " InitOrder: a_=" << a_
<< " b_=" << b_ << " c_=" << c_ << std::endl;
}
};
int main()
{
// ------------------------------------------------------------------
// Demo 1: Default, parameterized, and overloaded constructors
// ------------------------------------------------------------------
std::cout << "=== Point Constructors ===" << std::endl;
Point p1; // default
Point p2(3.0, 4.0); // parameterized (two args)
Point p3(5.0); // overloaded (one arg)
Point p4(p2); // copy constructor
std::cout << " p1 = "; p1.print(); std::cout << std::endl;
std::cout << " p2 = "; p2.print(); std::cout << std::endl;
std::cout << " p3 = "; p3.print(); std::cout << std::endl;
std::cout << " p4 = "; p4.print(); std::cout << " (copy of p2)" << std::endl;
std::cout << std::endl;
// ------------------------------------------------------------------
// Demo 2: const and reference members require initializer list
// ------------------------------------------------------------------
std::cout << "=== Member Initializer List (const/ref) ===" << std::endl;
int aliceGrade = 95;
int bobGrade = 88;
Student alice("Alice", 20, 3.8, aliceGrade);
Student bob("Bob", 22, 3.5, bobGrade);
alice.print();
bob.print();
std::cout << std::endl;
// ------------------------------------------------------------------
// Demo 3: Object lifecycle (construction and destruction order)
// ------------------------------------------------------------------
std::cout << "=== Object Lifecycle ===" << std::endl;
std::cout << " Entering block:" << std::endl;
{
LifecycleDemo a("First");
LifecycleDemo b("Second");
LifecycleDemo c("Third");
std::cout << " --- inside block ---" << std::endl;
// Destructors called in REVERSE order when block exits
}
std::cout << " Block exited." << std::endl;
std::cout << std::endl;
// ------------------------------------------------------------------
// Demo 4: Copy constructor is called in these situations
// ------------------------------------------------------------------
std::cout << "=== When Copy Constructor is Called ===" << std::endl;
std::cout << " 1. Direct initialization:" << std::endl;
Point original(1.0, 2.0);
Point copy1(original); // explicit copy
std::cout << " 2. Assignment-style initialization:" << std::endl;
Point copy2 = original; // also calls copy constructor (NOT assignment)
std::cout << " 3. Pass by value to function:" << std::endl;
// (We'll just note this - calling a function that takes Point by value)
std::cout << " (copy is made when passing to function by value)" << std::endl;
std::cout << std::endl;
// ------------------------------------------------------------------
// Demo 5: DynamicArray with multiple constructors
// ------------------------------------------------------------------
std::cout << "=== DynamicArray Constructors ===" << std::endl;
{
std::cout << " Creating arrays:" << std::endl;
DynamicArray arr1; // default
arr1.push(10);
arr1.push(20);
arr1.push(30);
DynamicArray arr2(8); // custom capacity
arr2.push(100);
arr2.push(200);
int initData[] = {1, 2, 3, 4, 5};
DynamicArray arr3(initData, 5); // from array
DynamicArray arr4(arr3); // deep copy
std::cout << std::endl;
std::cout << " arr1: "; arr1.print(); std::cout << std::endl;
std::cout << " arr2: "; arr2.print(); std::cout << std::endl;
std::cout << " arr3: "; arr3.print(); std::cout << std::endl;
std::cout << " arr4: "; arr4.print(); std::cout << " (copy of arr3)" << std::endl;
std::cout << std::endl;
std::cout << " Destructors will fire:" << std::endl;
}
std::cout << std::endl;
// ------------------------------------------------------------------
// Demo 6: Multiple constructor overloads (Rectangle)
// ------------------------------------------------------------------
std::cout << "=== Rectangle Constructor Overloads ===" << std::endl;
Rectangle r1; // default
Rectangle r2(5.0); // square
Rectangle r3(4.0, 6.0); // rectangle
Rectangle r4(10.0, 20.0, 30.0, 40.0); // positioned
Rectangle r5("player", 100.0, 200.0, 50.0, 50.0); // named
r1.print();
r2.print();
r3.print();
r4.print();
r5.print();
std::cout << std::endl;
// ------------------------------------------------------------------
// Demo 7: Initialization order
// ------------------------------------------------------------------
std::cout << "=== Member Initialization Order ===" << std::endl;
std::cout << " Members initialize in DECLARATION order:" << std::endl;
InitOrder io(10);
std::cout << " (a_=10, b_=20, c_=30 regardless of init-list order)" << std::endl;
std::cout << std::endl;
// ------------------------------------------------------------------
// Demo 8: Array of objects (default constructor required)
// ------------------------------------------------------------------
std::cout << "=== Array of Objects ===" << std::endl;
std::cout << " Creating array of 3 Points (default constructor x3):" << std::endl;
Point arr[3]; // calls default constructor 3 times
std::cout << " arr[0] = "; arr[0].print(); std::cout << std::endl;
std::cout << " arr[1] = "; arr[1].print(); std::cout << std::endl;
std::cout << " arr[2] = "; arr[2].print(); std::cout << std::endl;
return 0;
}
/*
Expected output:
=== Point Constructors ===
Point() default constructor -> (0, 0)
Point(3, 4) parameterized constructor
Point(5) single-value constructor
Point(copy) copy constructor -> (3, 4)
p1 = (0, 0)
p2 = (3, 4)
p3 = (5, 5)
p4 = (3, 4) (copy of p2)
=== Member Initializer List (const/ref) ===
ID:1001 Alice Age:20 GPA:3.8
ID:1002 Bob Age:22 GPA:3.5
=== Object Lifecycle ===
Entering block:
[CONSTRUCT] First
[CONSTRUCT] Second
[CONSTRUCT] Third
--- inside block ---
[DESTROY] Third
[DESTROY] Second
[DESTROY] First
Block exited.
=== When Copy Constructor is Called ===
1. Direct initialization:
Point(1, 2) parameterized constructor
Point(copy) copy constructor -> (1, 2)
2. Assignment-style initialization:
Point(copy) copy constructor -> (1, 2)
3. Pass by value to function:
(copy is made when passing to function by value)
=== DynamicArray Constructors ===
Creating arrays:
DynamicArray() - capacity 4
DynamicArray(8)
DynamicArray(array, 5)
DynamicArray(copy) - deep copy
arr1: [10, 20, 30] (size=3, cap=4)
arr2: [100, 200] (size=2, cap=8)
arr3: [1, 2, 3, 4, 5] (size=5, cap=5)
arr4: [1, 2, 3, 4, 5] (size=5, cap=5) (copy of arr3)
Destructors will fire:
~DynamicArray() - freeing 5 ints
~DynamicArray() - freeing 5 ints
~DynamicArray() - freeing 8 ints
~DynamicArray() - freeing 4 ints
=== Rectangle Constructor Overloads ===
default: pos(0,0) size(1x1) area=1
square: pos(0,0) size(5x5) area=25
rect: pos(0,0) size(4x6) area=24
positioned: pos(10,20) size(30x40) area=1200
player: pos(100,200) size(50x50) area=2500
=== Member Initialization Order ===
Members initialize in DECLARATION order:
InitOrder: a_=10 b_=20 c_=30
(a_=10, b_=20, c_=30 regardless of init-list order)
=== Array of Objects ===
Creating array of 3 Points (default constructor x3):
Point() default constructor -> (0, 0)
Point() default constructor -> (0, 0)
Point() default constructor -> (0, 0)
arr[0] = (0, 0)
arr[1] = (0, 0)
arr[2] = (0, 0)
*/
Run command
g++ -std=c++98 -Wall -Wextra -o example constructors.cpp