Object-Oriented Principles in C++
C++ implements three core object-oriented princpiles: encapsulation, inheritance, and polymorphism. Objects represent entities with porperties and behaviors. For example:
- A
Personobject might have properties like name and age, with behaviors like speak() and walk() - A
Vehicleobject could have properties like wheels and engine, with behaviors like accelerate()
I. Encapsulation
Encapsulation bundles data and methods that operate on that data. It controls access through three specifiers:
public: Accessible anywhereprotected: Accessible within class and derived classesprivate: Accessible only within class
class AccessDemo {
public:
string publicData;
protected:
string protectedData;
private:
string privateData;
public:
void setData() {
publicData = "Public";
protectedData = "Protected";
privateData = "Private";
}
};
int main() {
AccessDemo obj;
obj.publicData = "Accessible"; // OK
// obj.protectedData = "Error"; // Compiler error
}
Constructors initialize objects, while destructors handle cleanup. Initializer lists provide efficient member initialization.
class Point3D {
public:
Point3D(int x, int y, int z) : coordX(x), coordY(y), coordZ(z) {}
void display() {
cout << "X: " << coordX << "\nY: " << coordY << "\nZ: " << coordZ;
}
private:
int coordX, coordY, coordZ;
};
int main() {
Point3D p(10, 20, 30);
p.display();
}
The this pointer refers to the current instance and helps resolve name conflicts. Only non-static members consume per-object memory.
class MemoryLayout {
int instanceVar; // Consumes memory per object
static int classVar; // Shared across instances
public:
void memberFunc() {} // No per-object memory
static void staticFunc() {} // No per-object memory
};
int MemoryLayout::classVar = 0;
int main() {
cout << sizeof(MemoryLayout); // Output: 4 (size of int)
}
Friend declarations grant external funcsions or classes access to private members.
class SecureData {
friend class DataAccessor;
double secretValue;
};
class DataAccessor {
public:
void modify(SecureData& data) {
data.secretValue = 42.0; // Allowed through friendship
}
};
Operators can be redefined for custom types. This example shows vector addition:
Vector2D operator+(const Vector2D& rhs) {
return Vector2D(x + rhs.x, y + rhs.y);
}
double x, y;
};
int main() { Vector2D v1(1.0, 2.0), v2(3.0, 4.0); Vector2D result = v1 + v2; // Uses overloaded operator }
</div>### VI. Inheritance
Inheritance enables code reuse through hierarchical relationships. Access control affects member visibility:
<div class="code-block">```
class Base {
public:
int pubMem;
protected:
int protMem;
private:
int privMem;
};
class PublicDerived : public Base {
// pubMem remains public
// protMem remains protected
};
class ProtectedDerived : protected Base {
// Both pubMem and protMem become protected
};
class PrivateDerived : private Base {
// Both pubMem and protMem become private
};
Polymorphism enables different behaviors through a common interface. Virtual functions enable runtime binding.
class Shape {
public:
virtual void draw() { cout << "Drawing shape\n"; }
};
class Circle : public Shape {
public:
void draw() override { cout << "Drawing circle\n"; }
};
class Square : public Shape {
public:
void draw() override { cout << "Drawing square\n"; }
};
void renderShape(Shape& s) {
s.draw(); // Calls appropriate implementation
}
int main() {
Circle c;
Square s;
renderShape(c); // Output: Drawing circle
renderShape(s); // Output: Drawing square
}