OOP & C++ Cheat Sheet

cpp-oop Last verified: 28 Jul 2026

The four OOP pillars — quick reference

PillarDefinitionC++ mechanism
EncapsulationBundling data and methods together, hiding internal stateAccess specifiers (private, protected, public)
AbstractionShowing only essential features, hiding implementationAbstract classes, pure virtual functions
InheritanceA class acquiring properties/behavior of another classclass Derived : access-specifier Base
PolymorphismOne interface, many implementationsFunction 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
};
SpecifierSame classDerived classOutside class
privateYesNoNo
protectedYesYesNo
publicYesYesYes

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

TypeWhen it runsNotes
Default constructorNo arguments givenAuto-generated if you define no constructor at all
Parameterized constructorCalled with argumentsLets you initialize members at creation
Copy constructorObject copied from another of the same typeSignature: ClassName(const ClassName &obj)
DestructorObject goes out of scope / delete calledOne 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

PropertyBehavior
Static data memberShared across ALL objects of the class — one copy total, not one per object
Static member functionCan access only static data; has no this pointer
DeclarationDeclared 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

TypeStructure
SingleOne base, one derived
MultipleOne derived, two or more base classes
MultilevelA → B → C chain
HierarchicalOne base, multiple derived classes
HybridCombination of the above

Effect of inheritance access specifier

Base memberpublic inheritanceprotected inheritanceprivate inheritance
publicstays publicbecomes protectedbecomes private
protectedstays protectedstays protectedbecomes private
privatenot accessiblenot accessiblenot 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

TypeAlso calledMechanismResolved
Compile-timeStatic / early bindingFunction overloading, operator overloadingAt compile time
RuntimeDynamic / late bindingVirtual functionsAt 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
}
KeywordPurpose
tryWraps code that might throw
throwRaises an exception
catchHandles 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
RuleWhy it matters
Every new needs a matching deleteOtherwise: memory leak
Every new[] needs a matching delete[]Using plain delete on an array causes undefined behavior
new throws bad_alloc on failureUnlike C’s malloc, which returns NULL
delete on a NULL pointerSafe — it’s a no-op, unlike dereferencing NULL

STL — quick container reference

ContainerUnderlying structureAccessInsert/Delete
vectorDynamic arrayO(1) random accessO(1) amortized at end, O(n) elsewhere
listDoubly linked listO(n)O(1) anywhere (given iterator)
dequeDouble-ended arrayO(1)O(1) at both ends
stackAdapter (usually over deque)Top onlyO(1) push/pop
queueAdapter (usually over deque)Front/back onlyO(1) push/pop
mapRed-Black tree (sorted)O(log n)O(log n)
unordered_mapHash tableO(1) avgO(1) avg
setRed-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

TrapRule
Overloading vs OverridingOverloading = same name, different parameters, compile-time. Overriding = same signature in derived class, runtime, needs virtual.
Virtual destructorBase 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 accessstruct defaults to public, class defaults to private. That is the only functional difference.
Private inheritanceALL inherited members (even public ones) become private in the derived class — they’re still there, just inaccessible from outside.
Pure virtual functionvirtual void f() = 0; makes the class abstract. You CAN have a pointer/reference to it, just not an instance.
Constructor/destructor orderBase constructs first, derived constructs second. Destruction is the exact reverse.
Static memberONE copy shared by all objects — not per-object.
this pointerImplicitly passed to every non-static member function; NOT available in static member functions.
Reference vs pointerA 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 triggerCalled 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 ambiguityOverloading only by return type is NOT allowed — the parameter list must differ.
Diamond problemFixed with virtual inheritance, so the shared base class has only one copy in the final derived object.
Array deletenew[] must be paired with delete[], never plain delete — mismatching them is undefined behavior.
Template instantiationTemplates 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.