CDAC C-CAT · NEXT CYCLE: FEBRUARY 2027 BATCH UPDATED JULY 2026

OOP & C++ Cheat Sheet

Classes, constructors, inheritance, polymorphism, operator overloading, templates, exception handling, and STL basics — the complete OOP/C++ reference for CDAC C-CAT.

No login required
Cross-checked against syllabus
Updated July 2026
On this page

The four OOP pillars — quick reference

Pillar Definition C++ mechanism
Encapsulation Bundling data and methods together, hiding internal state Access specifiers (private, protected, public)
Abstraction Showing only essential features, hiding implementation Abstract classes, pure virtual functions
Inheritance A class acquiring properties/behavior of another class class Derived : access-specifier Base
Polymorphism One interface, many implementations Function overloading, operator overloading, virtual functions

Classes & access specifiers

class Student {
private:
    int rollNo;          // accessible only inside the class
protected:
    string name;          // accessible inside class + derived classes
public:
    int marks;            // accessible from anywhere
};
Specifier Same class Derived class Outside class
private Yes No No
protected Yes Yes No
public Yes Yes Yes

By default, class members are private; struct members are public — this default-access difference is a common trap question.

PYQ

By default, members of a struct in C++ are:

  • A) private
  • B) public
  • C) protected
  • D) Depends on compiler

Why: C++ struct members default to public; class members default to private. This is the only real functional difference between struct and class in C++.

Constructors & destructors

Type When it runs Notes
Default constructor No arguments given Auto-generated if you define no constructor at all
Parameterized constructor Called with arguments Lets you initialize members at creation
Copy constructor Object copied from another of the same type Signature: ClassName(const ClassName &obj)
Destructor Object goes out of scope / delete called One per class, no arguments, no return type, name is ~ClassName()
class Point {
    int x, y;
public:
    Point() : x(0), y(0) {}                  // default constructor, initializer list
    Point(int a, int b) : x(a), y(b) {}       // parameterized constructor
    Point(const Point &p) : x(p.x), y(p.y) {} // copy constructor
    ~Point() {}                               // destructor
};

Construction/destruction order in inheritance

Construction order: Base class constructor  → Derived class constructor
Destruction order:  Derived class destructor → Base class destructor

(Destructor order is always the reverse of constructor order.)

PYQ

In a derived class object, which constructor executes first?

  • A) Base class constructor
  • B) Derived class constructor
  • C) Both run simultaneously
  • D) Order is undefined

Why: The base class must be fully constructed before the derived class can build on top of it. Destructors then run in the reverse order.

The this pointer

class Box {
    int side;
public:
    Box(int side) {
        this->side = side;  // disambiguates member vs parameter with the same name
    }
    Box& setSide(int s) {
        this->side = s;
        return *this;       // enables method chaining: box.setSide(1).setSide(2);
    }
};

this is a pointer to the calling object, implicitly passed to every non-static member function.

Static members

Property Behavior
Static data member Shared across ALL objects of the class — one copy total, not one per object
Static member function Can access only static data; has no this pointer
Declaration Declared inside the class, defined/initialized outside with ClassName::
class Counter {
public:
    static int count;   // declaration
    Counter() { count++; }
};
int Counter::count = 0;  // definition, required outside the class

PYQ

If a class has a static data member, how many copies of it exist for 100 objects of that class?

  • A) 100
  • B) 1
  • C) 0
  • D) Depends on constructor

Why: A static member belongs to the class itself, not to any individual object — every object shares the same single copy.

Inheritance types

Type Structure
Single One base, one derived
Multiple One derived, two or more base classes
Multilevel A → B → C chain
Hierarchical One base, multiple derived classes
Hybrid Combination of the above

Effect of inheritance access specifier

Base member public inheritance protected inheritance private inheritance
public stays public becomes protected becomes private
protected stays protected stays protected becomes private
private not accessible not accessible not accessible

The diamond problem

       A
      / \
     B   C
      \ /
       D

D inherits from both B and C, which both inherit from A.
D ends up with TWO copies of A's members — ambiguous.

Fix: virtual inheritance
   class B : virtual public A {};
   class C : virtual public A {};
   → D now gets only ONE shared copy of A.

PYQ

What problem does virtual inheritance solve?

  • A) Slow function calls
  • B) The diamond problem (duplicate base class copies)
  • C) Memory leaks
  • D) Operator overloading conflicts

Why: Without virtual inheritance, a class inheriting from two classes that share a common base ends up with duplicate copies of that base's members. Virtual inheritance ensures only one shared copy exists.

Polymorphism — compile-time vs runtime

Type Also called Mechanism Resolved
Compile-time Static / early binding Function overloading, operator overloading At compile time
Runtime Dynamic / late binding Virtual functions At runtime, via the vtable

Function overloading

void print(int x);
void print(double x);
void print(string x);
// Same name, different parameter list — resolved at compile time

Virtual functions & the vtable

class Shape {
public:
    virtual void draw() { cout << "Shape"; }   // virtual — enables runtime polymorphism
};
class Circle : public Shape {
public:
    void draw() override { cout << "Circle"; } // overrides base version
};

Shape* s = new Circle();
s->draw();  // prints "Circle" — decided at RUNTIME via the vtable, not compile time

Without virtual, s->draw() would call Shape::draw() based on the pointer's declared type, not the object's actual type — this is the single most commonly tested OOP concept on CCAT.

Pure virtual functions & abstract classes

class Shape {
public:
    virtual void draw() = 0;  // pure virtual — makes Shape an ABSTRACT class
};
// Shape s;        // ERROR — cannot instantiate an abstract class
// Shape* s = new Circle(); // OK — pointer/reference to abstract class is fine

A class with at least one pure virtual function cannot be instantiated directly; any derived class MUST override it to become concrete (instantiable).

Virtual destructors — a critical exam trap

class Base {
public:
    virtual ~Base() {}   // MUST be virtual if the class will be used polymorphically
};
class Derived : public Base {
public:
    ~Derived() { /* cleanup */ }
};

Base* b = new Derived();
delete b;  // Without a virtual destructor, only ~Base() runs — Derived's cleanup is SKIPPED (memory/resource leak)

PYQ

What happens if you delete a derived class object through a base class pointer, and the base destructor is NOT virtual?

  • A) Compile error
  • B) Both destructors run normally
  • C) Only the base class destructor runs — derived cleanup is skipped
  • D) Only the derived destructor runs

Why: Without a virtual destructor, the compiler resolves the destructor call using the pointer's static (declared) type, not the object's actual type — this causes undefined behavior/resource leaks and is a classic CCAT trap.

PYQ

A class with a pure virtual function is called a/an ___ class.

  • A) Static
  • B) Final
  • C) Abstract
  • D) Friend

Why: A pure virtual function (declared with = 0) makes the class abstract — it cannot be instantiated and exists to define an interface for derived classes.

Operator overloading

class Complex {
    int real, imag;
public:
    Complex(int r, int i) : real(r), imag(i) {}
    Complex operator+(const Complex &c) {
        return Complex(real + c.real, imag + c.imag);
    }
};
Complex c3 = c1 + c2;  // calls operator+ automatically

Operators that CANNOT be overloaded

::   (scope resolution)
.    (member access)
.*   (pointer-to-member access)
?:   (ternary/conditional)
sizeof
typeid

PYQ

Which of the following operators CANNOT be overloaded in C++?

  • A) +
  • B) ==
  • C) ::
  • D) []

Why: The scope resolution operator (::), member access (.), pointer-to-member (.*), ternary (?:), sizeof, and typeid cannot be overloaded in C++.

Friend functions & friend classes

class Box {
    int width;
public:
    Box(int w) : width(w) {}
    friend void printWidth(Box b);  // friend function — NOT a member, but has private access
};

void printWidth(Box b) {
    cout << b.width;  // allowed, because printWidth is declared a friend
}

A friend function is not a member of the class (no this pointer, not inherited, not affected by access specifiers itself) but can access the class's private and protected members.

Templates — generic programming

// Function template
template <typename T>
T maxVal(T a, T b) {
    return (a > b) ? a : b;
}
maxVal(3, 7);       // T deduced as int
maxVal(3.5, 2.1);   // T deduced as double

// Class template
template <typename T>
class Stack {
    T arr[100];
    int top = -1;
public:
    void push(T x) { arr[++top] = x; }
    T pop() { return arr[top--]; }
};
Stack<int> intStack;
Stack<string> strStack;

Templates enable compile-time generic programming — one code definition, many types, with no runtime overhead (unlike, say, Java generics with type erasure).

Exception handling

try {
    int arr[5];
    int idx = 10;
    if (idx >= 5) throw out_of_range("Index out of bounds");
    arr[idx] = 1;
} catch (const out_of_range &e) {
    cout << "Caught: " << e.what();
} catch (...) {
    cout << "Unknown exception";  // catch-all handler
}
Keyword Purpose
try Wraps code that might throw
throw Raises an exception
catch Handles a specific exception type
catch(...) Catches any exception type (catch-all)

Multiple catch blocks are checked top to bottom — order matters. A catch(...) block must come last, or it will swallow every exception before more specific handlers get a chance.

PYQ

In a sequence of catch blocks, what happens if catch(...) is placed FIRST, before specific exception handlers?

  • A) Compile error
  • B) It catches everything, so the later specific catch blocks become unreachable
  • C) It is ignored
  • D) No difference — order doesn't matter

Why: Catch blocks are evaluated in order, and catch(...) matches any exception type — placing it first means no later, more specific catch block will ever execute.

Memory management — new/delete

int* p = new int(5);      // allocate single int on heap
delete p;                 // deallocate

int* arr = new int[10];   // allocate array on heap
delete[] arr;             // MUST use delete[] for arrays, not delete
Rule Why it matters
Every new needs a matching delete Otherwise: memory leak
Every new[] needs a matching delete[] Using plain delete on an array causes undefined behavior
new throws bad_alloc on failure Unlike C's malloc, which returns NULL
delete on a NULL pointer Safe — it's a no-op, unlike dereferencing NULL

STL — quick container reference

Container Underlying structure Access Insert/Delete
vector Dynamic array O(1) random access O(1) amortized at end, O(n) elsewhere
list Doubly linked list O(n) O(1) anywhere (given iterator)
deque Double-ended array O(1) O(1) at both ends
stack Adapter (usually over deque) Top only O(1) push/pop
queue Adapter (usually over deque) Front/back only O(1) push/pop
map Red-Black tree (sorted) O(log n) O(log n)
unordered_map Hash table O(1) avg O(1) avg
set Red-Black tree (sorted, unique) O(log n) O(log n)

PYQ

Which STL container guarantees elements are stored in sorted order automatically?

  • A) vector
  • B) unordered_map
  • C) map
  • D) list

Why: std::map is implemented as a self-balancing binary search tree (typically Red-Black), which keeps keys in sorted order automatically. unordered_map uses hashing and gives no ordering guarantee.

CDAC C-CAT — top OOP/C++ exam traps

Trap Rule
Overloading vs Overriding Overloading = same name, different parameters, compile-time. Overriding = same signature in derived class, runtime, needs virtual.
Virtual destructor Base class destructor MUST be virtual if you'll delete a derived object through a base pointer — otherwise derived cleanup is skipped.
struct vs class default access struct defaults to public, class defaults to private. That is the only functional difference.
Private inheritance ALL inherited members (even public ones) become private in the derived class — they're still there, just inaccessible from outside.
Pure virtual function virtual void f() = 0; makes the class abstract. You CAN have a pointer/reference to it, just not an instance.
Constructor/destructor order Base constructs first, derived constructs second. Destruction is the exact reverse.
Static member ONE copy shared by all objects — not per-object.
this pointer Implicitly passed to every non-static member function; NOT available in static member functions.
Reference vs pointer A reference must be initialized at declaration and can never be reseated to refer to something else. A pointer can be NULL and reassigned.
Copy constructor trigger Called on: pass-by-value, return-by-value, and explicit copy initialization — NOT on simple assignment of an already-constructed object (that's the assignment operator instead).
Function overloading ambiguity Overloading only by return type is NOT allowed — the parameter list must differ.
Diamond problem Fixed with virtual inheritance, so the shared base class has only one copy in the final derived object.
Array delete new[] must be paired with delete[], never plain delete — mismatching them is undefined behavior.
Template instantiation Templates generate actual code only when instantiated with a specific type — this happens at compile time, not runtime.

PYQs are indicative of exam style, not guaranteed exact repeats.

AD SLOT — insert <ins class="adsbygoogle"> unit here once AdSense is approved