Introduction to OOP in C++

⚡ Need a fast revision version? See the OOP & C++ Cheat Sheet →

Most programmers learn to code procedurally first — write a function, pass it some data, get a result back. Object-Oriented Programming (OOP) asks a different question: instead of writing functions that act on data, what if the data and the functions that belong to it travel together, as one unit?

That unit is called an object, and C++ was one of the first mainstream languages to bring this style to a C-like syntax. For the CDAC C-CAT exam, this topic shows up constantly — both as standalone conceptual questions and as “predict the output” code snippets, so a shaky grasp here costs marks in two different sections at once.

Procedural vs Object-Oriented Programming

In plain C, data and the functions that operate on it are separate:

struct Student {
    char name[50];
    int marks;
};

void printStudent(struct Student s) {
    printf("%s scored %d\n", s.name, s.marks);
}

Nothing stops any other function in the program from reaching into s.marks directly and changing it however it likes. There’s no concept of “this data belongs to this behavior.”

C++ lets you bind them together:

class Student {
private:
    string name;
    int marks;

public:
    Student(string n, int m) : name(n), marks(m) {}

    void print() {
        cout << name << " scored " << marks << endl;
    }
};

Now marks and the print() function that knows how to display it live inside the same Student type. That’s the shift OOP makes: from “functions that take data” to “objects that have behavior.”

Classes and Objects

A class is a blueprint. An object is an actual instance built from that blueprint — with its own copy of the data.

Student s1("Anita", 92);
Student s2("Rahul", 85);

s1.print();  // Anita scored 92
s2.print();  // Rahul scored 85

s1 and s2 are two separate objects of the same class — same blueprint, independent data.

The Four Pillars of OOP

1. Encapsulation

Bundling data with the functions that operate on it, and controlling access to that data from outside. In the Student example above, name and marks are private — code outside the class can’t touch them directly. The only way in is through the public functions the class chooses to expose.

class Account {
private:
    double balance;

public:
    Account(double initial) : balance(initial) {}

    void deposit(double amount) {
        if (amount > 0) balance += amount;
    }

    double getBalance() { return balance; }
};

balance can only ever change through deposit() — which can enforce rules (like rejecting negative amounts) that direct access would bypass entirely.

2. Abstraction

Exposing what something does while hiding how it does it. When you call s1.print(), you don’t need to know whether it uses cout, builds a string first, or writes to a file — the class hides that detail behind a simple interface.

In C++, abstraction is often taken further with abstract classes — classes with at least one pure virtual function, which can’t be instantiated directly and exist purely to define an interface:

class Shape {
public:
    virtual double area() = 0;  // pure virtual — no body here
};

class Circle : public Shape {
    double radius;
public:
    Circle(double r) : radius(r) {}
    double area() override { return 3.14159 * radius * radius; }
};

Shape defines that every shape must have an area(), without saying anything about how each shape computes it.

3. Inheritance

A new class (derived class) can reuse and extend an existing class (base class), instead of rewriting shared behavior from scratch.

class Animal {
public:
    void eat() { cout << "This animal eats food." << endl; }
};

class Dog : public Animal {
public:
    void bark() { cout << "Woof!" << endl; }
};

Dog d;
d.eat();   // inherited from Animal
d.bark();  // defined in Dog

Dog gets eat() for free just by inheriting from Animal, and adds its own bark() on top.

4. Polymorphism

Literally “many forms” — the same function call behaving differently depending on the object it’s called on. C++ gives you this in two ways:

Compile-time (function overloading):

int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }

The compiler picks the right version based on argument types, at compile time.

Run-time (virtual functions):

class Shape {
public:
    virtual void draw() { cout << "Drawing a shape" << endl; }
};

class Square : public Shape {
public:
    void draw() override { cout << "Drawing a square" << endl; }
};

Shape* s = new Square();
s->draw();  // "Drawing a square" — resolved at runtime, not compile time

Even though s is declared as a Shape*, calling draw() on it runs Square’s version — because draw() is virtual. This is the single most common source of “predict the output” trick questions in CCAT’s OOP section, so it’s worth sitting with this example until it’s genuinely obvious why the output isn’t “Drawing a shape.”

Why OOP Matters for the CDAC C-CAT Exam

CCAT doesn’t usually ask you to design a class hierarchy from scratch. It asks you to read one — a class, a derived class, a constructor or destructor, maybe a virtual function — and predict what gets printed, or identify which pillar a snippet demonstrates. That means:

  • You need to be fluent enough in the syntax that reading a 15-line class definition doesn’t slow you down.
  • You need to know constructor/destructor call order when objects are created and destroyed (base class first, derived class last — and destructors in the reverse order).
  • You need to recognize virtual function behavior on sight, since it reliably trips people who’ve only memorized the four pillars as definitions rather than seeing them in running code.

Summary

  • OOP binds data and the behavior that acts on it into a single unit — an object, built from a class blueprint.
  • Encapsulation controls access to an object’s data from the outside.
  • Abstraction exposes what something does while hiding how.
  • Inheritance lets a class reuse and extend another class’s behavior.
  • Polymorphism lets the same call behave differently — at compile time (overloading) or run time (virtual functions).
  • For CCAT specifically, prioritize being able to read and trace through class-based code, not just recite the four pillars as definitions.

Frequently Asked Questions

1 Is C++ a purely object-oriented language?

No — C++ is a hybrid language. It supports OOP (classes, inheritance, polymorphism) but also lets you write plain procedural code with standalone functions and no classes at all, unlike a purely OOP language like Java where every piece of code must live inside a class.

2 What's the difference between a class and a struct in C++?

Functionally almost nothing — both can have member functions, constructors, and inheritance. The only real difference is the default access level: class members are private by default, struct members are public by default. By convention, struct is used for simple data containers and class is used for types with real behavior.

3 Do I need to know OOP theory, or just the C++ syntax, for CCAT?

Both. CCAT's OOP questions mix conceptual ones ("which pillar does this describe?") with code-reading ones ("what does this program output?"). Knowing the four pillars by name isn't enough if you can't trace through a constructor/destructor call order or a virtual function call.