C++ Core Programming: Memory Management, References and OOP Fundamentals
Memory Layout in C++
- Code Area: Stores binary code of functions managed by the operating system
- Global Area: Holds global variables, static variables, and constents
- Stack Area: Automatically allocated and deallocated by compiler for function parameters and local variables
- Heap Area: Manually managed by programmer for dynamic allocation
Pre-execution Memory Segments
Before program execution, the executable contains two main segments:
Code Segment: Contains machine instructions. It's shared among processes and read-only to prevent accidental modification.
Global Segment: Stores global and static variables along with constants like string literals.
Example:
int global_var = 10;
const int const_global = 20;
int main() {
int local_var = 30;
static int static_var = 40;
cout << "Local var address: " << &local_var << endl;
cout << "Global var address: " << &global_var << endl;
cout << "Static var address: " << &static_var << endl;
cout << "Const global address: " << &const_global << endl;
return 0;
}
Runtime Memory Areas
Stack Area: Automatic management by compiler for local variables and function parameters.
Important Note: Never return addresses of local variables as they're automatically released.
int* getLocalAddress() {
int local = 42;
return &local; // Dangerous!
}
int main() {
int* ptr = getLocalAddress();
cout << *ptr << endl; // Undefined behavior
return 0;
}
Heap Area: Manual allocation/deallocation required. Uses new operator.
int* createOnHeap() {
return new int(100);
}
int main() {
int* ptr = createOnHeap();
cout << *ptr << endl;
delete ptr;
return 0;
}
Reference Mechanism
Basic Usage
References provide alternative names for existing variables:
int value = 42;
int& alias = value; // Create reference
alias = 100; // Modifies original variable
cout << value << endl; // Outputs 100
Key Rules
- References must be initialized at declaration
- Cannot be reassigned after initialization
int a = 10;
int& ref = a; // Must initialize
int b = 20;
ref = b; // Assignment, not reassignment
Function Parameters
References enable modifying actual parameters:
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 10, y = 20;
swap(x, y);
cout << x << " " << y << endl; // Outputs 20 10
return 0;
}
Return Values
Functions can return references (but avoid returning local variables):
int& getReference() {
static int value = 42;
return value;
}
int main() {
int& ref = getReference();
ref = 100; // Modifies static variable
cout << ref << endl; // Outputs 100
return 0;
}
Function Overloading
Default Parameters
Function parameters can have default values:
int calculate(int a, int b = 10, int c = 20) {
return a + b + c;
}
int main() {
cout << calculate(5) << endl; // Uses defaults
return 0;
}
Function Overloading
Multiple functions with same name but different signatures:
void process(int x) {}
void process(double x) {}
void process(int x, double y) {}
int main() {
process(10);
process(3.14);
process(5, 2.5);
return 0;
}
Object-Orientde Programming
Class Design
Classes encapsulate data and behavior:
class Student {
public:
string name;
string id;
void display() {
cout << "Name: " << name << " ID: " << id << endl;
}
void setName(string n) { name = n; }
void setId(string i) { id = i; }
};
int main() {
Student s1;
s1.setName("Alice");
s1.setId("001");
s1.display();
return 0;
}
Access Control
Three access levels:
public: Accessible from anywhereprotected: Accessible within class and derived classesprivate: Accessible only within class
class Person {
public:
string name;
protected:
string car;
private:
int id;
};
int main() {
Person p;
p.name = "John"; // OK
// p.car = "BMW"; // Error - protected
return 0;
}
Constructor and Destructor
class Person {
public:
Person() { cout << "Constructor called" << endl; }
~Person() { cout << "Destructor called" << endl; }
};
int main() {
Person p; // Constructor called
return 0; // Destructor called
}
Copy Constructor
class Person {
public:
Person(const Person& other) {
// Deep copy implementation
age = other.age;
}
};
Operator Overloading
Arithmetic Operators
class Vector {
public:
int x, y;
Vector operator+(const Vector& other) {
Vector result;
result.x = x + other.x;
result.y = y + other.y;
return result;
}
};
Stream Operators
ostream& operator<<(ostream& out, const Vector& v) {
out << "(" << v.x << ", " << v.y << ")";
return out;
}
Increment Operators
Vector& operator++() { // Prefix
x++;
y++;
return *this;
}
Vector operator++(int) { // Postfix
Vector temp = *this;
x++;
y++;
return temp;
}
Inheritance
Basic Syntax
class Base {
public:
virtual void display() { cout << "Base" << endl; }
};
class Derived : public Base {
public:
void display() override { cout << "Derived" << endl; }
};
Virtual Functions
class Animal {
public:
virtual void speak() { cout << "Animal speaks" << endl; }
};
class Dog : public Animal {
public:
void speak() override { cout << "Dog barks" << endl; }
};
void makeSound(Animal& animal) {
animal.speak(); // Dynamic binding
}
File Operations
Text Files
// Writing
ofstream outFile("data.txt");
outFile << "Hello World" << endl;
outFile.close();
// Reading
ifstream inFile("data.txt");
string line;
while (getline(inFile, line)) {
cout << line << endl;
}
inFile.close();
Binary Files
struct Data {
int id;
char name[32];
};
// Writing
ofstream file("data.bin", ios::binary);
Data d = {1, "John"};
file.write(reinterpret_cast<char*>(&d), sizeof(d));
file.close();
// Reading
ifstream readFile("data.bin", ios::binary);
Data readData;
readFile.read(reinterpret_cast<char*>(&readData), sizeof(readData));
readFile.close();
Advanced Concepts
Pure Virtual Functions
class AbstractClass {
public:
virtual void pureFunction() = 0; // Pure virtual
};
class ConcreteClass : public AbstractClass {
public:
void pureFunction() override { cout << "Implementation" << endl; }
};
Virtual Destructors
class Base {
public:
virtual ~Base() { /* Cleanup */ }
};
File Stream Modes
ios::in: Read modeios::out: Write modeios::binary: Binary modeios::app: Append modeios::trunc: Truncate existing file