๐จ
Chapter 6
Classes and Objects
Deep dive into constructors, destructors, operator overloading, inheritance, and templates.
6.1 Constructors and Destructors
Special methods for object initialization and cleanup.
| Aspect | Definition | Example |
|---|---|---|
| Constructor | Special method invoked when object is created. |
class Tesla { Tesla() { ... } };
|
| Destructor | Special method invoked when object is destroyed. |
~Tesla() { ... }
|
| Default Constructor | No arguments, initializes default values. |
Tesla() { battery = 0; }
|
| Parameterized Constructor | Accepts arguments to initialize data. |
Tesla(int b) { battery = b; }
|
| Destructor Use Case | Frees resources, cleans up memory. |
Called when object goes out of scope
|
โถ Constructors and Destructors Example
#include <iostream>
using namespace std;
class Tesla {
private:
string model;
int batteryLevel;
int* data; // Dynamic memory
public:
// Default constructor
Tesla() {
model = "Unknown";
batteryLevel = 0;
data = nullptr;
cout << "Default constructor called" << endl;
}
// Parameterized constructor
Tesla(string m, int battery) {
model = m;
batteryLevel = battery;
data = new int[10]; // Allocate memory
cout << "Parameterized constructor called for " << model << endl;
}
// Copy constructor
Tesla(const Tesla& other) {
model = other.model;
batteryLevel = other.batteryLevel;
data = new int[10];
cout << "Copy constructor called for " << model << endl;
}
// Destructor
~Tesla() {
if (data != nullptr) {
delete[] data; // Free memory
}
cout << "Destructor called for " << model << endl;
}
void display() {
cout << "Model: " << model << ", Battery: " << batteryLevel << "%" << endl;
}
};
int main() {
cout << "Creating objects:" << endl;
Tesla car1; // Default constructor
car1.display();
Tesla car2("Model 3", 85); // Parameterized constructor
car2.display();
Tesla car3 = car2; // Copy constructor
car3.display();
cout << endl << "Objects going out of scope..." << endl;
return 0;
// Destructors called automatically
}
Click "Run Code" to execute
6.2 Operator Overloading
Redefining the behavior of operators for user-defined types.
| Aspect | Definition | Example |
|---|---|---|
| Operator Overloading | Redefine operator behavior for custom types. |
Tesla operator+(Tesla t1, Tesla t2);
|
| Syntax | Defined using operator keyword. |
Tesla operator+(Tesla t);
|
| Overloading + | Adds two objects. |
Tesla t3 = t1 + t2;
|
| Overloading == | Compares two objects. |
bool operator==(Tesla t1, Tesla t2);
|
| Use Case | Simplifies object manipulation. |
Mathematical operations on custom objects
|
โถ Operator Overloading Example
#include <iostream>
using namespace std;
class Complex {
private:
float real, imag;
public:
Complex() : real(0), imag(0) {}
Complex(float r, float i) : real(r), imag(i) {}
// Overload + operator
Complex operator+(const Complex& c) {
Complex temp;
temp.real = real + c.real;
temp.imag = imag + c.imag;
return temp;
}
// Overload - operator
Complex operator-(const Complex& c) {
Complex temp;
temp.real = real - c.real;
temp.imag = imag - c.imag;
return temp;
}
// Overload == operator
bool operator==(const Complex& c) {
return (real == c.real && imag == c.imag);
}
// Overload << operator for output
friend ostream& operator<<(ostream& out, const Complex& c) {
out << c.real;
if (c.imag >= 0)
out << " + " << c.imag << "i";
else
out << " - " << (-c.imag) << "i";
return out;
}
// Overload >> operator for input
friend istream& operator>>(istream& in, Complex& c) {
cout << "Enter real part: ";
in >> c.real;
cout << "Enter imaginary part: ";
in >> c.imag;
return in;
}
};
int main() {
Complex c1(3.5, 2.5);
Complex c2(1.5, 4.5);
cout << "c1 = " << c1 << endl;
cout << "c2 = " << c2 << endl;
Complex c3 = c1 + c2;
cout << "c1 + c2 = " << c3 << endl;
Complex c4 = c1 - c2;
cout << "c1 - c2 = " << c4 << endl;
if (c1 == c2) {
cout << "c1 and c2 are equal" << endl;
} else {
cout << "c1 and c2 are not equal" << endl;
}
return 0;
}
Click "Run Code" to execute
โถ Tesla Operator Overloading Example
#include <iostream>
using namespace std;
class Tesla {
private:
int batteryLevel;
public:
Tesla(int battery = 0) : batteryLevel(battery) {}
// Overload + to combine battery levels
Tesla operator+(const Tesla& t) {
return Tesla(this->batteryLevel + t.batteryLevel);
}
// Overload ++ (prefix)
Tesla& operator++() {
batteryLevel += 10;
if (batteryLevel > 100) batteryLevel = 100;
return *this;
}
// Overload ++ (postfix)
Tesla operator++(int) {
Tesla temp = *this;
batteryLevel += 10;
if (batteryLevel > 100) batteryLevel = 100;
return temp;
}
void display() {
cout << "Battery: " << batteryLevel << "%" << endl;
}
};
int main() {
Tesla car1(50);
Tesla car2(30);
cout << "Car 1: ";
car1.display();
cout << "Car 2: ";
car2.display();
Tesla car3 = car1 + car2;
cout << "Combined battery: ";
car3.display();
++car1;
cout << "After ++car1: ";
car1.display();
car2++;
cout << "After car2++: ";
car2.display();
return 0;
}
Click "Run Code" to execute
6.3 Inheritance
Mechanism to derive new classes from existing classes.
| Aspect | Definition | Example |
|---|---|---|
| Inheritance | Derive new class from existing class. |
class EV : public Car { ... };
|
| Single Inheritance | One derived class from one base class. |
class Sedan : public Car { ... };
|
| Multiple Inheritance | One derived class from multiple base classes. |
class TeslaEV : public Car, public Engine { ... };
|
| Hierarchical Inheritance | Multiple derived classes from one base class. |
Truck, SUV from Car
|
| Use Case | Code reusability, method overriding. |
Common base class logic shared
|
โถ Inheritance Example
#include <iostream>
using namespace std;
// Base class
class Vehicle {
protected:
string brand;
int year;
public:
Vehicle(string b, int y) : brand(b), year(y) {
cout << "Vehicle constructor" << endl;
}
void displayInfo() {
cout << "Brand: " << brand << endl;
cout << "Year: " << year << endl;
}
virtual ~Vehicle() {
cout << "Vehicle destructor" << endl;
}
};
// Single Inheritance
class Car : public Vehicle {
protected:
int doors;
public:
Car(string b, int y, int d) : Vehicle(b, y), doors(d) {
cout << "Car constructor" << endl;
}
void displayCarInfo() {
displayInfo();
cout << "Doors: " << doors << endl;
}
~Car() {
cout << "Car destructor" << endl;
}
};
// Multilevel Inheritance
class ElectricCar : public Car {
private:
int batteryCapacity;
public:
ElectricCar(string b, int y, int d, int battery)
: Car(b, y, d), batteryCapacity(battery) {
cout << "ElectricCar constructor" << endl;
}
void displayFullInfo() {
displayCarInfo();
cout << "Battery: " << batteryCapacity << " kWh" << endl;
}
~ElectricCar() {
cout << "ElectricCar destructor" << endl;
}
};
int main() {
cout << "Creating ElectricCar object:" << endl;
ElectricCar tesla("Tesla", 2024, 4, 100);
cout << endl << "Displaying information:" << endl;
tesla.displayFullInfo();
cout << endl << "Object going out of scope:" << endl;
return 0;
}
Click "Run Code" to execute
6.4 Templates
Create generic functions and classes that work with any data type.
| Aspect | Definition | Example |
|---|---|---|
| Templates | Create generic functions or classes. |
template <typename T>
|
| Function Templates | Generic function for multiple types. |
T add(T a, T b) { return a + b; }
|
| Class Templates | Generic class for multiple types. |
template <typename T> class Tesla { ... };
|
| Template Specialization | Customize templates for specific types. |
template<> class Tesla<string> { ... };
|
| Use Case | Code reusability, type safety. |
Generic containers like vector, list
|
โถ Function Templates Example
#include <iostream>
using namespace std;
// Function template
template <typename T>
T getMax(T a, T b) {
return (a > b) ? a : b;
}
// Function template with multiple parameters
template <typename T>
void swapValues(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
// Overloaded function template
template <typename T>
T add(T a, T b) {
return a + b;
}
template <typename T>
T add(T a, T b, T c) {
return a + b + c;
}
int main() {
// Using template with int
cout << "Max of 10 and 20: " << getMax(10, 20) << endl;
// Using template with double
cout << "Max of 3.5 and 2.8: " << getMax(3.5, 2.8) << endl;
// Using template with char
cout << "Max of 'a' and 'z': " << getMax('a', 'z') << endl;
// Swap function
int x = 5, y = 10;
cout << endl << "Before swap: x = " << x << ", y = " << y << endl;
swapValues(x, y);
cout << "After swap: x = " << x << ", y = " << y << endl;
// Add function
cout << endl << "Add two integers: " << add(5, 10) << endl;
cout << "Add three integers: " << add(5, 10, 15) << endl;
cout << "Add two doubles: " << add(3.5, 2.5) << endl;
return 0;
}
Click "Run Code" to execute
โถ Class Templates Example
#include <iostream>
using namespace std;
// Class template
template <typename T>
class Array {
private:
T* arr;
int size;
public:
Array(int s) {
size = s;
arr = new T[size];
}
~Array() {
delete[] arr;
}
void setElement(int index, T value) {
if (index >= 0 && index < size) {
arr[index] = value;
}
}
T getElement(int index) {
if (index >= 0 && index < size) {
return arr[index];
}
return T();
}
void display() {
cout << "Array elements: ";
for (int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
};
// Template class for a pair
template <typename T1, typename T2>
class Pair {
private:
T1 first;
T2 second;
public:
Pair(T1 f, T2 s) : first(f), second(s) {}
void display() {
cout << "(" << first << ", " << second << ")" << endl;
}
T1 getFirst() { return first; }
T2 getSecond() { return second; }
};
int main() {
// Array of integers
Array<int> intArray(5);
for (int i = 0; i < 5; i++) {
intArray.setElement(i, (i + 1) * 10);
}
intArray.display();
// Array of doubles
Array<double> doubleArray(3);
doubleArray.setElement(0, 3.14);
doubleArray.setElement(1, 2.71);
doubleArray.setElement(2, 1.41);
doubleArray.display();
// Pair examples
Pair<int, int> p1(10, 20);
cout << endl << "Integer pair: ";
p1.display();
Pair<string, int> p2("Tesla", 369);
cout << "String-Int pair: ";
p2.display();
Pair<double, string> p3(3.14, "Pi");
cout << "Double-String pair: ";
p3.display();
return 0;
}
Click "Run Code" to execute
๐ก Practice Exercise
Master classes and objects with these exercises:
- Create a class with constructor, destructor, and copy constructor
- Overload arithmetic operators for a custom class
- Implement a class hierarchy with inheritance
- Create a template function that works with different data types
- Build a template class for a stack data structure