Skip to content

C++ Object Oriented

A primary motivation for C++‘s creation was to add object-oriented capabilities to the C language. OOP is a programming paradigm based on the concept of “objects”, which can contain data in the form of fields (often known as attributes or properties) and code in the form of procedures (often known as methods).

In OOP, we model real-world or abstract entities as objects. For instance, a Car object might have properties like color, make, model, and methods like startEngine(), accelerate(), brake(). This approach helps manage complexity in large software systems by organizing code around data.

Several core concepts underpin object-oriented programming:

A class is a blueprint or template for creating objects. It defines the properties (data members) and methods (member functions) that all objects of that class will have. Defining a class doesn’t create an object itself, but specifies what objects of that type will look like and how they will behave.

// Class definition (blueprint)
class Dog {
public:
// Data members (properties)
std::string breed;
int age;
std::string name;
// Member functions (methods)
void bark() {
std::cout << name << " says Woof!\n";
}
};

An object is an instance of a class. It’s a concrete entity created from the class blueprint, residing in memory. Each object has its own copy of the class’s data members (unless they are static). You interact with objects by calling their methods.

// Creating objects (instances) of the Dog class
Dog myDog;
myDog.name = "Buddy";
myDog.breed = "Golden Retriever";
myDog.age = 3;
Dog anotherDog;
anotherDog.name = "Lucy";
myDog.bark(); // Output: Buddy says Woof!
anotherDog.bark(); // Output: Lucy says Woof!

Encapsulation means bundling the data (attributes) and the methods that operate on that data within a single unit (the class/object). It also involves controlling access to the internal state of an object, often by making data members private or protected and providing public methods (getters and setters) to interact with the data in a controlled manner. This protects the object’s internal state from unintended external modification, a concept known as data hiding.

class BankAccount {
private:
double balance; // Data is hidden
public:
BankAccount(double initialBalance) : balance(initialBalance) {}
void deposit(double amount) { // Controlled access
if (amount > 0) {
balance += amount;
}
}
double getBalance() const { // Controlled access
return balance;
}
};

Abstraction means hiding complex implementation details and exposing only the essential features or interfaces to the user. Users interact with an object through its public methods without needing to know how those methods are implemented internally. Think of driving a car: you use the steering wheel, pedals, and shifter (the interface), without needing to understand the complex mechanics underneath (the implementation). In C++, classes provide abstraction through their public interfaces (public methods and sometimes data).

Inheritance allows a new class (derived class) to acquire the properties and methods of an existing class (base class). This promotes code reuse and establishes an “is-a” relationship (e.g., a Square is a Shape). The derived class can extend the base class by adding new members or modify inherited behavior (method overriding).

class Animal { // Base class
public:
virtual void speak() const { std::cout << "Animal sound\n"; }
virtual ~Animal() = default;
};
class Cat : public Animal { // Derived class
public:
void speak() const override { std::cout << "Meow\n"; } // Overrides base method
};

Polymorphism (from Greek, meaning “many forms”) allows objects of different classes to be treated as objects of a common base class. The most common form in C++ is runtime polymorphism, achieved through virtual functions and inheritance. It means a call to a member function will cause a different function to be executed depending on the actual type of the object being referred to at runtime, typically via a base class pointer or reference.

void makeAnimalSpeak(const Animal& animal) { // Takes a reference to the base class
animal.speak(); // Calls the correct 'speak' based on the actual object type
}
Cat myCat;
Animal* animalPtr = &myCat;
makeAnimalSpeak(myCat); // Output: Meow
animalPtr->speak(); // Output: Meow (through base pointer)

Function overloading and operator overloading are forms of compile-time polymorphism. They allow multiple functions or operators with the same name but different parameter lists (for functions) or operand types (for operators) to exist within the same scope. The compiler determines which version to call based on the arguments or operands provided at the call site.

int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
// The compiler chooses based on arguments:
add(5, 3); // Calls the int version
add(2.5, 3.1); // Calls the double version

OOP provides a powerful set of tools for designing flexible, maintainable, and reusable software.