Skip to main content

C/C++

OOP in C++ Explained: Classes to Polymorphism

·

Object-Oriented Programming in C++: classes, inheritance, and polymorphism diagram

Object-oriented programming (OOP) organizes code around objects rather than procedures. C++ supports OOP natively and is one of the most widely used languages for teaching the paradigm. This post covers the 4 core pillars (objects, classes, inheritance, polymorphism, encapsulation, and abstraction) with working C++ examples for each.

Diagram showing OOP concepts in C++: classes, objects, inheritance, and polymorphism

Objects

An object is a self-contained unit that pairs data (attributes) with the functions that operate on that data (methods). Objects are the building blocks of OOP and give you a way to model real-world entities directly in code.

A car, for example, can be an object. Its attributes are color, make, model, and year. Its methods are accelerate(), brake(), and turn(). The data and the behavior live together in one unit.

Classes

A class is the blueprint for creating objects. It declares the data members (attributes) and member functions (methods) that every object of that class carries.

In C++, the class keyword defines a class. Here is a Person class with 2 data members and 4 member functions:

class Person {
    private:
        string name;
        int age;

    public:
        void setName(string n) {
            name = n;
        }

        void setAge(int a) {
            age = a;
        }

        string getName() {
            return name;
        }

        int getAge() {
            return age;
        }
};

name and age are private so outside code cannot touch them directly. The 4 public functions (setName, setAge, getName, getAge) form the controlled interface.

Create an object from that class and call its methods like this:

Person p;
p.setName("Alice");
p.setAge(25);

string name = p.getName();  // "Alice"
int age     = p.getAge();   // 25

OOP in C++ is built on 4 pillars: Inheritance, Polymorphism, Encapsulation, and Abstraction.

Inheritance

Inheritance lets one class acquire the properties of another. The class that inherits is the derived class (or subclass); the class it inherits from is the base class (or superclass).

Use the public access specifier to inherit publicly from a base class. Here, Student inherits from Person and adds a rollNumber field:

class Student : public Person {
    private:
        int rollNumber;

    public:
        void setRollNumber(int r) {
            rollNumber = r;
        }

        int getRollNumber() {
            return rollNumber;
        }
};

Student inherits name and age from Person, so you call setName, setAge, and the new roll-number methods on the same object:

Student s;
s.setName("Mary");
s.setAge(20);
s.setRollNumber(101);

string name      = s.getName();        // "Mary"
int age          = s.getAge();         // 20
int rollNumber   = s.getRollNumber();  // 101

Polymorphism

Polymorphism lets a single interface work across objects of different derived types. C++ has 2 forms.

Compile-time polymorphism (static) is resolved at compile time via function overloading and operator overloading. The compiler picks the right overload based on the argument types.

Runtime polymorphism (dynamic) is resolved at runtime via virtual functions and function overriding. Declare a function virtual in the base class; derived classes override it. The correct version runs based on the actual object type, not the pointer type.

Here is printDetails declared virtual in Person and overridden in Student:

class Person {
    private:
        string name;
        int age;

    public:
        void setName(string n) { name = n; }
        void setAge(int a)     { age = a; }
        string getName()       { return name; }
        int getAge()           { return age; }

        virtual void printDetails() {
            cout << "Name: " << name << endl;
            cout << "Age: "  << age  << endl;
        }
};

class Student : public Person {
    private:
        int rollNumber;

    public:
        void setRollNumber(int r) { rollNumber = r; }
        int getRollNumber()       { return rollNumber; }

        void printDetails() override {
            cout << "Name: "        << getName()        << endl;
            cout << "Age: "         << getAge()         << endl;
            cout << "Roll Number: " << getRollNumber()  << endl;
        }
};

Call printDetails through a base-class pointer and the runtime dispatches to the correct override:

Person*  p = new Person();
Student* s = new Student();

p->setName("John");  p->setAge(30);
s->setName("Mary");  s->setAge(20);  s->setRollNumber(101);

p->printDetails();  // prints Name + Age
s->printDetails();  // prints Name + Age + Roll Number

Get help with your C++ assignment from working developers

Encapsulation

Encapsulation combines data and the functions that manage it into a single class, and restricts direct access to the data from outside. Private members are the enforcement mechanism.

A BankAccount class demonstrates this. The balance field is private; the only way to change it is through deposit and withdraw:

class BankAccount {
    private:
        float balance;

    public:
        BankAccount() {
            balance = 0;
        }

        void deposit(float amount) {
            balance += amount;
        }

        void withdraw(float amount) {
            if (balance >= amount) {
                balance -= amount;
            }
        }

        float getBalance() {
            return balance;
        }
};

balance is readable via getBalance() and writable only through deposit() or withdraw(). Outside code cannot accidentally set balance = -999:

BankAccount account;
account.deposit(1000);
cout << account.getBalance();  // 1000

account.withdraw(500);
cout << account.getBalance();  // 500

Abstraction

Abstraction hides implementation details behind a common interface. In C++, pure virtual functions create abstract classes that define what derived classes must implement, without specifying how.

Declare a function as = 0 to make it pure virtual. A class with at least one pure virtual function is abstract and cannot be instantiated directly:

class Shape {
    public:
        virtual float area()      = 0;
        virtual float perimeter() = 0;
};

Derived classes inherit Shape and provide concrete implementations:

class Rectangle : public Shape {
    private:
        float length;
        float width;

    public:
        Rectangle(float l, float w) : length(l), width(w) {}

        float area() override {
            return length * width;
        }

        float perimeter() override {
            return 2 * (length + width);
        }
};

A Circle or Triangle class would follow the same pattern, each providing its own area() and perimeter(). Code that works with Shape* pointers works with any of them without knowing the concrete type.

Practical Design Notes

4 habits that save debugging time when writing OOP code in C++:

  1. Design class responsibilities first. Decide what each class owns and what it delegates before writing any code. A class that does too many things is the most common cause of tangled inheritance chains.
  2. Use access specifiers to enforce boundaries. private on data members and public on the interface is the baseline. Only expose what callers actually need.
  3. Name classes and methods after what they represent. getBalance() is clear. getValue() on the same class is not.
  4. Avoid global variables inside class-heavy code. Pass state through constructors or method parameters. Global variables and OOP class design work against each other.

For a deeper look at when to use inheritance versus other patterns, see Inheritance vs Composition and C++ Best Practices: How to Write Code Like a Pro.

OOP in C++ applies directly to coursework in data structures, algorithms, and systems programming. If you are stuck on a class design problem or an assignment involving virtual dispatch, the developers at C++ Programming Assignment Help work through these exact problems daily.

Share: X / Twitter LinkedIn

Related articles

  • C/C++

    Min Heap and Max Heap in C++

    Build min heaps and max heaps in C++ with std::priority_queue and the STL heap algorithms, plus array math, heapify, heap sort, and worked examples.

    Sep 19, 2023

  • C/C++

    Python vs C++: Which Should You Learn?

    A direct comparison of Python and C++ across syntax, speed, memory management, OOP, and use cases to help you pick the right language.

    Sep 17, 2023

  • C/C++

    Vectors in C++: A Complete Guide

    Master std::vector in C++ with declaration, push_back and emplace_back, iterators, size vs capacity, 2D vectors, custom types, and complexity, with code that compiles.

    Aug 7, 2023

← All articles

Stuck on a programming assignment?

Get expert help in Java, C++, Python, JavaScript, SQL, and more. We deliver working code with a clear walkthrough so you can understand and defend it.