optional · CSS study notes
Core OOP Concepts (extended)
- Data Abstraction: exposing only essential features of an object while hiding implementation detail ("what it does," not "how it does it")
- Encapsulation: bundling data (attributes) and methods (behavior) into a single unit (class), typically restricting direct access to internal state via access modifiers (
private,protected,public) - Inheritance: a mechanism where a new class (derived/child) acquires properties and behavior of an existing class (base/parent), enabling code reuse and hierarchical classification
- Polymorphism: "many forms" — the ability of different objects/classes to respond to the same interface/message in type-specific ways; achieved via function overloading (compile-time) and virtual functions (runtime)
C++ Example — One Per Pillar
Abstraction — hide implementation, expose only what's needed:
class BankAccount
{
private:
double balance; // hidden -- implementation detail
public:
void deposit(double amt) { balance += amt; }
double getBalance() const { return balance; }
};
Encapsulation — bundle data + methods, control access:
class Employee
{
private:
double salary; // hidden data
public:
void setSalary(double s) { if (s > 0) salary = s; } // controlled write
double getSalary() const { return salary; }
};
Inheritance — reuse a base class's members:
class Animal
{
public:
void eat() { cout << "Eating...\n"; }
};
class Dog : public Animal // Dog "is-a" Animal
{
public:
void bark() { cout << "Barking...\n"; }
};
// Dog d; d.eat(); d.bark(); -- eat() is reused, not rewritten
Polymorphism — same interface, different behavior:
class Printer
{
public:
void print(int i) { cout << "int: " << i << "\n"; }
void print(double d) { cout << "double: " << d << "\n"; }
};
// Same function name "print" behaves differently per argument type --
// compile-time polymorphism (function overloading). Runtime
// polymorphism via virtual functions is covered on the dedicated page.
Also Frequently Tested
- Message passing: objects communicate by invoking each other's member functions — calling
obj.method(args)is "sending obj a message"; sometimes listed as a supporting OOP feature alongside the four core pillars - Benefits of OOP (common short-answer question): code reusability (inheritance), data security (encapsulation), reduced complexity (abstraction), flexibility/extensibility (polymorphism), easier maintenance
MCQ Trap
- Encapsulation and Data Abstraction are related but distinct: abstraction is about hiding complexity/showing only essentials; encapsulation is the mechanism (bundling + access control) that achieves it.
- Message passing isn't unique to OOP — what makes it distinctly OOP is that the message is sent to an object, which itself decides how to respond (ties directly into polymorphism)
Main Characteristic of Object-Oriented Paradigm (procedural vs OOP)
| Aspect | Procedural (e.g. C) | Object-Oriented (e.g. C++) |
|---|---|---|
| Organizing unit | Functions | Objects (data + functions bundled together) |
| Data & function relationship | Separate — data passed between free-standing functions | Coupled — data and the functions that operate on it live inside one class |
| Data security | Global data freely accessible, error-prone | Access control via private/protected/public |
| Code reuse | Copy-paste or function reuse | Inheritance — extend existing classes without rewriting |
| Real-world modeling | Step-by-step procedures | Entities/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 — this single shift is what enables encapsulation, inheritance, and polymorphism to work together.
Quick illustration — all four pillars in one class
#include <iostream>
using namespace std;
class Account // Encapsulation: data + behavior bundled together
{
private:
double balance; // hidden — Abstraction: user doesn't need to know internal representation
public:
Account(double initial) : balance(initial) {} // Constructor
void deposit(double amt) { balance += amt; } // controlled access, not direct field manipulation
double getBalance() const { return balance; }
};
class SavingsAccount : public Account // Inheritance: reuses Account's behavior
{
public:
SavingsAccount(double initial) : Account(initial) {}
void addInterest() { deposit(getBalance() * 0.05); } // extends behavior
};
Polymorphism isn't shown here (needs virtual — see the Polymorphism page) but this snippet demonstrates encapsulation, abstraction, and inheritance working together in a single realistic example.
Self-Test Questions
- What is the single defining shift that separates OOP from procedural programming?
- Give one advantage of bundling data and functions into a class instead of keeping them separate.