CSS Prepare

optional · CSS study notes

2. Main Characteristic of Object-Oriented Paradigm

AspectProcedural (e.g. C)Object-Oriented (e.g. C++)
Organizing unitFunctionsObjects (data + functions bundled together)
Data & function relationshipSeparate — data passed between free-standing functionsCoupled — data and the functions that operate on it live inside one class
Data securityGlobal data freely accessible, error-proneAccess control via private/protected/public
Code reuseCopy-paste or function reuseInheritance — extend existing classes without rewriting
Real-world modelingStep-by-step proceduresEntities/objects, closer to how real systems are structured

The defining characteristic examiners look for: OOP models a system as a set of interacting objects, each bundling its own data and behavior, rather than as a sequence of procedures acting on shared data.

class Account
{
private:
    double balance;
public:
    Account(double initial) : balance(initial) {}
    void deposit(double amt) { balance += amt; }
    double getBalance() const { return balance; }
};

A single class bundling data (balance) and behavior (deposit, getBalance) — this bundling is the core shift from procedural code.

Why this distinction is tested

Examiners ask "what is THE main characteristic of OOP" expecting a single, precise answer — not a list of the four pillars. The precise answer: OOP organizes a program around objects (bundled data + behavior) rather than around a sequence of procedures acting on shared data. Everything else (encapsulation, inheritance, polymorphism) follows from this one structural shift.

Side-by-side: solving the same problem, two ways

Procedural approach — data and functions are separate:

struct Account { double balance; };
void deposit(struct Account* a, double amt) { a->balance += amt; }
// Any function anywhere can touch a->balance directly -- no protection

OOP approach — data and functions are bundled, access is controlled:

class Account
{
private:
    double balance;
public:
    void deposit(double amt) { balance += amt; }   // only this class can touch balance directly
};

Consequences that follow from this one shift

  • Data hiding becomes possible — since data lives inside the object, access modifiers can restrict it
  • Code becomes reusable through inheritance — because behavior is attached to a class, not floating as free functions
  • Objects map naturally to real-world entities — a Car object behaves like an actual car conceptually, aiding design and communication among developers

Important MCQs

  1. The single most defining characteristic of OOP, as distinct from procedural programming, is:
    • a) Use of loops and conditionals b) Organizing code around objects that bundle data and behavior c) Faster compilation d) Absence of functions
  2. In procedural programming, data is typically:
    • a) Bundled with functions b) Global/shared and accessed by many functions freely c) Always private d) Inaccessible
  3. Which of these follows directly from OOP's core structural shift (bundling data + behavior)?
    • a) Faster runtime always b) Ability to apply access control (data hiding) c) No need for classes d) Removal of functions
  4. A struct Account with a free function deposit(Account*, double) is an example of:
    • a) OOP encapsulation b) Procedural style — data and function are separate c) Polymorphism d) Inheritance

✅ Self-Test Questions (with Answers)

Q1. In one sentence, state the single defining characteristic of OOP (not just a list of pillars).

Ans: Object-oriented programming organises a program around objects — self-contained units that bundle data (state) together with the functions (behaviour) that operate on that data — instead of around a sequence of procedures acting on separate, shared data. That one structural shift is the answer examiners want; everything else follows from it as a consequence rather than as a parallel point:

  • Because the data now lives inside a boundary, access control (private/protected/public) becomes possible at all — hence encapsulation and data hiding.
  • Because behaviour is attached to a type rather than floating as free functions, that type can be extended — hence inheritance.
  • Because a call is made on an object, the object's real type can decide which function runs — hence run-time polymorphism via virtual functions.
  • Because the public interface is separated from the hidden representation, the user sees only essentials — hence abstraction.

MCQ trap: if a question asks for the main characteristic (singular), do not simply recite "encapsulation, inheritance, polymorphism, abstraction." Those are the four pillars built on the characteristic; the characteristic itself is the bundling of data and behaviour into objects.

Q2. Using the procedural vs OOP code above, explain why the procedural version is more error-prone.

Ans: In the procedural version the balance field of struct Account is public by default and lives outside any protective boundary, so any function in any translation unit that can reach the struct's address can overwrite it directly — a->balance = -9999; compiles happily. There is no single place that guarantees the invariant "balance must never go negative," so the same validation has to be repeated in every function that touches the field, and one forgotten check corrupts the data. The OOP version makes balance private, so the compiler itself rejects outside access and the only route in is deposit(), which can enforce the invariant once, in one place. This is encapsulation doing real work: it converts a run-time bug that appears anywhere into a compile-time error at the point of misuse, and it narrows the amount of code you must audit when the invariant breaks from the whole program down to one class.

// Procedural: nothing stops this
struct Account { double balance; };
Account a{100};
a.balance -= 5000;          // compiles -- account silently goes to -4900

// OOP: the compiler stops it
class Account {
    double balance;                       // private by default in a class
public:
    explicit Account(double b) : balance(b) {}
    bool withdraw(double amt) {
        if (amt <= 0 || amt > balance) return false;   // invariant enforced ONCE
        balance -= amt; return true;
    }
    double getBalance() const { return balance; }
};
Account b(100);
// b.balance -= 5000;       // ERROR: 'balance' is a private member of 'Account'
b.withdraw(5000);           // returns false -- state stays valid

A second, subtler benefit: because clients never name balance, the class can later change its representation (say to an integer count of paisa, to avoid floating-point error) without breaking a single line of caller code — the public interface is the only contract.

📌 Sample & Repeated FPSC Questions (2016–2026)

2023, Paper I, Q4(c) (6 marks) — Differentiate between Abstraction & Encapsulation.

Abstraction is a design-level concept: hiding unnecessary implementation complexity and exposing only the essential features of an object ("what it does"), achieved via abstract classes, interfaces, or well-designed public method signatures. Encapsulation is an implementation-level mechanism: bundling data and the methods that operate on it into one unit, and restricting direct external access to internal state ("how it's hidden"), typically via access specifiers, exposing controlled access only through public getters/setters.

In short: abstraction hides complexity from the user's perspective (interface design); encapsulation hides/protects data from unauthorized access (implementation protection). They work together — encapsulation is often the very mechanism used to enforce abstraction.

MCQ Trap: don't treat these as synonyms — a "differentiate" question wants the design-vs-implementation distinction, not two re-phrasings of the same idea.


2019, Paper I, Q4(a) (10 marks) — How do the OOP paradigm can be associated with the real-world problems? Explain.

OOP models software as objects combining state and behaviour, mirroring how real-world entities naturally are (a car has attributes and behaviours). This mapping helps because:

  • Classes map onto real entity types (Customer, Order, Account), easing communication with stakeholders.
  • Inheritance mirrors natural taxonomies/specialisation (SavingsAccount is-a Account).
  • Encapsulation mirrors hidden internal workings (you drive a car without knowing engine internals).
  • Polymorphism mirrors how different objects respond differently to the same action ("make a sound" differs for a Dog vs a Cat).
  • Association/aggregation/composition model real relationships (a Car has-a Engine; a University has-a Departments).

Exam angle: this is the "why OOP matters" essay question — score well by walking through all four pillars with one real-world analogy each, not just abstraction alone.


2026, Paper I, Q4 (1 mark, MCQ) — A class needs to allow different implementations of a method. What concept to use?

  • A) Inheritance
  • B) Polymorphism ✓
  • C) Encapsulation
  • D) None of these

Explanation: Polymorphism allows the same method name/signature to have different implementations across classes (via overriding), so the version that actually runs depends on the object's real type.