Object-Oriented Programming
OOP organizes code around objects — bundles of data (fields) and behavior (methods). It models the world as interacting objects with identity, state, and behavior.
Core Concepts
Classes and Objects
A class is a blueprint defining the structure and behavior. An object (instance) is a concrete realization.
CLASS Rectangle
FIELDS: width, height
CONSTRUCTOR NEW(width, height)
self.width ← width
self.height ← height
FUNCTION AREA()
RETURN self.width * self.height
PROCEDURE SCALE(factor)
self.width ← self.width * factor
self.height ← self.height * factor
Encapsulation
Hide internal state behind a public interface. Users interact with methods, not raw data.
CLASS BankAccount
PRIVATE balance // can't be accessed directly
CONSTRUCTOR NEW(initial)
self.balance ← initial
PROCEDURE DEPOSIT(amount)
self.balance ← self.balance + amount
FUNCTION WITHDRAW(amount)
IF amount > self.balance THEN RETURN Error("Insufficient funds")
self.balance ← self.balance - amount
RETURN Ok
FUNCTION BALANCE()
RETURN self.balance
Benefits: Invariants are maintained (balance can't go negative). Implementation can change without affecting users. Clear API contract.
Inheritance
A class (subclass/derived) inherits fields and methods from another class (superclass/base), extending or modifying behavior.
Single inheritance: Each class has at most one parent (Java, C#).
Multiple inheritance: A class can inherit from multiple parents (C++, Python). Leads to the diamond problem.
Rust's approach: No inheritance. Uses traits and composition instead. Traits provide shared behavior without inheritance hierarchies.
Diamond Problem
Animal
/ \
Flyable Swimmable
\ /
Duck
If both Flyable and Swimmable inherit from Animal and override a method, which version does Duck get?
Solutions: C++ uses virtual inheritance. Python uses Method Resolution Order (MRO / C3 linearization). Java avoids it by allowing only single class inheritance (interfaces can have default methods, resolved explicitly). Rust avoids it entirely — no class inheritance.
Polymorphism
One interface, multiple implementations. The ability to treat objects of different types uniformly.
Subtype Polymorphism (Dynamic Dispatch)
Call a method on an object — the actual method executed depends on the runtime type.
INTERFACE Shape
FUNCTION AREA() -> number
FUNCTION NAME() -> string
CLASS Circle IMPLEMENTS Shape
FIELDS: radius
FUNCTION AREA() RETURN PI * self.radius * self.radius
FUNCTION NAME() RETURN "Circle"
CLASS Square IMPLEMENTS Shape
FIELDS: side
FUNCTION AREA() RETURN self.side * self.side
FUNCTION NAME() RETURN "Square"
PROCEDURE PRINT_AREA(shape: Shape)
PRINT shape.NAME(), ": area = ", shape.AREA()
dyn Shape uses dynamic dispatch (vtable lookup at runtime).
Parametric Polymorphism (Generics)
Write code that works for any type satisfying certain constraints.
FUNCTION LARGEST(list) // works for any comparable type
max ← list[0]
FOR EACH item IN list[1..]
IF item > max THEN max ← item
RETURN max
Static dispatch: The compiler generates specialized code for each concrete type (monomorphization in Rust). Zero runtime overhead.
Ad-Hoc Polymorphism (Overloading)
Same function name, different behavior based on argument types.
- Operator overloading:
+works on integers, floats, strings (implementAddtrait in Rust). - Method overloading: Multiple methods with the same name but different parameter types (Java, C++). Rust doesn't support this directly.
Abstraction
Abstract classes: Can't be instantiated. Define interfaces that subclasses must implement.
Interfaces (Java) / Traits (Rust): Define a set of methods without implementation. Types that implement the trait/interface guarantee they provide those methods.
INTERFACE Drawable
PROCEDURE DRAW()
FUNCTION BOUNDING_BOX() -> Rect
// Any type implementing Drawable can be drawn
Composition vs Inheritance
"Favor composition over inheritance" — Gang of Four.
Inheritance (is-a): Cat IS-A Animal. Tight coupling. Fragile base class problem.
Composition (has-a): Car HAS-A Engine. Loose coupling. More flexible.
// Composition: Car has an Engine
CLASS Engine
FIELDS: horsepower
CLASS Car
FIELDS: engine (Engine), name (string)
PROCEDURE START()
PRINT "Starting ", self.engine.horsepower, " HP engine"
When to use inheritance: When there's a genuine "is-a" relationship and you want to substitute subclass objects where superclass is expected (Liskov Substitution).
When to use composition: Almost always. When you want to combine behaviors from multiple sources. When "has-a" is more natural than "is-a."
SOLID Principles
Single Responsibility (SRP)
A class should have one reason to change. Each class handles one concern.
Open-Closed (OCP)
Software entities should be open for extension but closed for modification. Add new behavior by adding new code, not changing existing code.
Liskov Substitution (LSP)
Subtypes must be substitutable for their base types without altering program correctness. If S is a subtype of T, objects of type S can replace objects of type T.
Violation example: Square extending Rectangle. If set_width and set_height are independent for Rectangle but coupled for Square, substitution breaks expectations.
Interface Segregation (ISP)
Clients should not be forced to depend on interfaces they don't use. Prefer many small, specific interfaces over one large one.
Dependency Inversion (DIP)
High-level modules should depend on abstractions, not concrete implementations. Both should depend on abstractions.
// Bad: UserService depends directly on PostgresDB
// Good: UserService depends on interface Database; PostgresDB implements Database
INTERFACE Database
PROCEDURE SAVE_USER(user)
Method Dispatch
Static Dispatch
Method resolved at compile time. No runtime overhead. Used with generics in Rust.
FUNCTION PROCESS(shape: Shape) // resolved at compile time (monomorphized)
Dynamic Dispatch (Vtable)
Method resolved at runtime via a virtual function table (vtable).
FUNCTION PROCESS(shape: Shape) // resolved at runtime (vtable lookup)
Vtable: A table of function pointers. Each trait object (dyn Trait) carries a pointer to data + a pointer to the vtable. Method call = load function pointer from vtable, call it. One level of indirection.
dyn Shape reference:
data_ptr → [Circle { radius: 5.0 }]
vtable_ptr → [area_fn_ptr, name_fn_ptr, drop_fn_ptr]
Object Layout in Memory
C++ objects: Fields laid out sequentially. Vtable pointer at the start (if virtual methods exist).
Rust trait objects: Fat pointer (data pointer + vtable pointer). No vtable pointer in the struct itself — only when used as dyn Trait.
Java objects: Object header (class pointer, hash code, lock info) + fields. All method calls go through vtable (except final/static methods, which are devirtualized by JIT).
Design Patterns Overview
Patterns are reusable solutions to common design problems (Gang of Four, 1994). Detailed coverage in software engineering topic.
| Category | Patterns | |---|---| | Creational | Singleton, Factory, Builder, Prototype | | Structural | Adapter, Decorator, Proxy, Composite, Facade | | Behavioral | Observer, Strategy, Command, Iterator, State |
OOP Criticisms
- Overuse of inheritance: Deep hierarchies are fragile and hard to refactor.
- Mutable shared state: Objects with mutable fields + references = bugs.
- Noun kingdom: Everything becomes a class, even when functions would be simpler (AbstractSingletonProxyFactoryBean).
- Concurrency: Mutable objects with locks are error-prone.
- Performance: Vtable indirection, cache-unfriendly layouts (pointer chasing), heap allocations.
Modern trend: Combine OOP with functional concepts. Rust uses traits without inheritance. Go uses interfaces without classes. Even Java added lambdas, records, and sealed classes.
Applications in CS
- GUI frameworks: Windows, buttons, panels — natural class hierarchies. Event handling via Observer pattern.
- Game development: Entity-Component-System (ECS) evolved from OOP. Game objects as compositions.
- Web frameworks: MVC pattern. Controllers, models, views as classes.
- Enterprise software: Domain-driven design. Rich domain models with behavior.
- Libraries/SDKs: Encapsulation provides stable APIs. Interface-based design enables extensibility.