Object Initialization and Cleanup
Proper object initialization and cleanup are critical for program safety. Uninitialized objects yield undefined behavior, while improper cleanup causes resource leaks. C++ uses constructors and destructors to address these issues:
Constructors
- Syntax:
ClassName() {} - No return type (not even void)
- Name matches class name
- Supports parameters and overloading
- Automatically invoked during object creation
Destructors
- Syntax:
~ClassName() {} - No return type or parameters
- Cannot be overloaded
- Automatically invoked before object destruction
#include <iostream>
using namespace std;
class Entity {
public:
Entity() { cout << "Constructor called" << endl; }
~Entity() { cout << "Destructor called" << endl; }
};
void testFunction() {
Entity localEntity; // Stack allocation
}
int main() {
Entity mainEntity;
testFunction();
Entity* heapEntity = new Entity; // Heap allocation
delete heapEntity;
return 0;
}
Constructor Types and Invocation
Constructors are categorized by parameters (parameterized/default) and type (regular/copy). Three invocation methods exist:
class Data {
public:
int value;
Data() : value(0) {
cout << "Default constructor: " << value << endl;
}
Data(int v) : value(v) {
cout << "Parameterized constructor: " << value << endl;
}
Data(const Data& src) : value(src.value) {
cout << "Copy constructor: " << value << endl;
}
};
void demo() {
Data d1; // Default
Data d2(5); // Explicit parameterized
Data d3(d2); // Copy
Data d4 = Data(10); // Explicit declaration
Data d5 = 15; // Implicit conversion
}
Copy Constructor Scenarios
Copy constructors are invoked in three cases:
- Initializing new objects from existing ones
- Passing objects by value to functions
- Returning objects by value from functions
class Counter {
public:
int count;
Counter(int c) : count(c) {}
Counter(const Counter& src) : count(src.count) {}
};
void increment(Counter c) {} // Copy during parameter passing
Counter createCounter() {
Counter temp(5);
return temp; // Potential copy during return
}
Constructor Rules
Compiler-provided special functions:
- Default constructor (parameterless)
- Default copy constructor (member-wise copy)
- Default destructor
Implementation rules:
- Defining any constructor suppresses default constructor generation
- Defining a copy constructor suppresses other constructor generatino
Static Members
Static Member Variables
- Shared across all class instances
- Initialized outside class definition
class SharedData {
public:
static int sharedValue;
};
int SharedData::sharedValue = 100;
Static Member Functions
- Can only access static members
- No
thispointer
class MathUtil {
public:
static double square(double x) { return x * x; }
};
Member Storage Separation
Only non-static data members reside within class objects:
class Empty {};
class WithData { int x; };
class WithStatic { static int y; };
// Sizes:
// Empty: 1 byte (minimum size)
// WithData: sizeof(int)
// WithStatic: sizeof(int) (static members don't contribute to size)
Deep vs Shallow Copy
Shallow copy duplicates pointers, leading to shared resources. Deep copy allocates new memory:
class Buffer {
int size;
char* data;
public:
Buffer(int sz) : size(sz), data(new char[sz]) {}
// Deep copy constructor
Buffer(const Buffer& src) : size(src.size), data(new char[src.size]) {
copy(src.data, src.data + size, data);
}
~Buffer() { delete[] data; }
};
Initialization Lists
Efficient member initialization syntax:
class Point {
int x, y, z;
public:
Point(int a, int b, int c) : x(a), y(b), z(c) {}
};
Object Composition
Clas members can be other objects. Construction order: member objects first, then container:
class Engine {
public:
Engine() { cout << "Engine built" << endl; }
};
class Car {
Engine powerplant;
public:
Car() { cout << "Car assembled" << endl; }
};
this Pointer
Implicit pointer to current instence, enabling member access and method chaining:
class Accumulator {
int total;
public:
Accumulator& add(int value) {
total += value;
return *this;
}
};
Accumulator acc;
acc.add(5).add(10).add(15); // Method chaining
Const Member Functions and Objects
Const member functions guarantee no state modification. Const objects can only call const methods:
class Immutable {
mutable int modifiable; // Can be changed in const methods
int fixed;
public:
void modify() const { modifiable = 1; } // Const method
void change() { fixed = 2; } // Non-const method
};
const Immutable obj;
obj.modify(); // Allowed
// obj.change(); // Error - const object cannot call non-const method