Classes & Objects

7 min read

Reading Progress0%
CS Fundamentals Index
Tier 1 -- Foundations
Tier 2 -- Core Concepts
Tier 3 -- Debugging & Tradeoffs
CS Fundamentals Index
Tier 1 -- Foundations
Tier 2 -- Core Concepts
Tier 3 -- Debugging & Tradeoffs

Classes & Objects

1. What Is It?

A is a blueprint describing what data a thing has (fields) and what it can do (methods). An is one concrete instance produced from that blueprint. If Car is a , your specific car toyota_at_VIN_123 is an .

Classes and objects solve a problem plain functions and structs don't handle well: bundling data with the behavior that operates on it, and doing so in a way that hides internal details from the rest of the program. Without them, related data and functions drift apart and grow tangled; with them, you can change a class's internals without touching every caller.

QUICK CHECK

A team is building a payment processing service. They store transaction data in a plain struct and handle all validation, formatting, and fee calculations in scattered utility functions throughout the codebase. When the fee calculation logic changes, they must hunt down and update every function that touches transaction data. Which design change best addresses this problem?

Choose one answer

2. How It Works

When you create an , memory is allocated for its fields, and the 's methods become callable through that . Each method implicitly knows which object it's operating on — that's what self (Python) or this (Java/C++) refers to.

# Python
class Circle:
    def __init__(self, radius):
        self.radius = radius            # instance field

    def area(self):                     # method; 'self' is the object
        return 3.14159 * self.radius ** 2

c = Circle(5)                            # construct
print(c.area())                          # 78.53975
// Java
public class Circle {
    private double radius;                        // field

    public Circle(double radius) {                // constructor
        this.radius = radius;
    }

    public double area() {                        // method
        return Math.PI * radius * radius;
    }
}

Circle c = new Circle(5);
System.out.println(c.area());
// C++
class Circle {
public:
    Circle(double radius) : radius_(radius) {}
    double area() const { return 3.14159 * radius_ * radius_; }
private:
    double radius_;
};

Circle c(5);                  // stack object
Circle* p = new Circle(5);    // heap object; must 'delete p' later

Construction and destruction

  • Constructor — runs when an object is created. Initializes fields, validates inputs.
  • Destructor — runs when the object is destroyed. Releases resources.

Python has __init__ (runs on creation) and __del__ (runs when garbage collected — unreliable timing). Java has constructors and finalize() (deprecated; don't use). C++ has constructors and destructors that run deterministically as ends — which is what enables RAII (Resource Acquisition Is Initialization: bind a resource's lifetime to an object, so the destructor releases it automatically when the object goes out of ).

Instance fields vs. class (static) fields

  • Instance field — one copy per object. self.radius in Python, field declarations in Java/C++.
  • field — one copy shared across all instances. Used for constants, counters, shared configuration.
class Counter:
    total = 0                 # class-level, shared
    def __init__(self):
        self.id = Counter.total
        Counter.total += 1

a = Counter(); b = Counter()
print(a.id, b.id, Counter.total)    # 0 1 2
public class Counter {
    static int total = 0;            // class-level
    int id;
    public Counter() { this.id = total++; }
}

Encapsulation: hiding internals

Objects expose a public API (methods) and hide their data. Callers should go through methods, not reach into fields. This lets you change the internal representation without breaking callers.

// Java — explicit access modifiers
public class Account {
    private double balance;
    public double getBalance() { return balance; }
    public void deposit(double amount) {
        if (amount <= 0) throw new IllegalArgumentException();
        balance += amount;
    }
}
# Python — convention, not enforcement
class Account:
    def __init__(self):
        self._balance = 0           # leading underscore = "internal"
    def deposit(self, amount):
        if amount <= 0: raise ValueError()
        self._balance += amount
    @property
    def balance(self): return self._balance   # read-only public view
QUICK CHECK

A backend service uses a DatabaseConnection class that opens a connection in the constructor. In C++, when a DatabaseConnection object goes out of scope, the destructor automatically closes the connection and releases resources — without the caller needing to do anything. What design principle does this demonstrate?

Choose one answer

3. What You Actually Need to Know

  • Methods are just functions that take the as a hidden first argument. Python makes it explicit (def area(self):); Java and C++ make it implicit (this is magic).
  • self / this resolves method calls to the right . c1.area() and c2.area() run the same code but on different data.
  • Don't expose internal state. Returning the internal list lets callers mutate it behind your back. Return a copy or an view.
  • Constructors should leave the object in a valid state — no "half-constructed" objects. If arguments are invalid, throw; don't leave fields at defaults.
  • Avoid "god classes". A with 30 methods and 15 fields usually wants to be two or three classes. One responsibility per is the rule of thumb — each class should have a single, clear reason to exist.
  • Python's access control is advisory. _name means "treat as private"; __name triggers name mangling but can still be reached. Java's private is compile-time enforced; C++'s private is also enforced.
  • Debugging clues:
    • AttributeError: ... has no attribute 'X' → you accessed a field that wasn't set (often forgotten in __init__).
    • NullPointerException on a field access → the field is a and was never initialized.
    • Uninitialized fields with garbage values (C++) → you declared but didn't initialize; use a constructor with an initializer list.
    • Shared state surprise across instances → you wrote to what looked like an instance field but was actually class-level.
QUICK CHECK

A ShoppingCart class stores items in an internal list and has a method get_items() that returns self._items directly. A developer calls cart.get_items().append('free_item') without going through any cart method. What problem does this cause, and what is the correct fix?

Choose one answer

4. Language Differences

AspectPythonJavaC++
Access controlConvention (_, __)Enforced (public/protected/private)Enforced (same keywords)
Everything is an object?YesNo — primitives aren'tNo — fundamental types aren't
Multiple inheritanceYes (MRO)No (only interfaces)Yes
Constructor syntax__init__ClassName(...)ClassName(...) with optional initializer list
Destructor__del__ (non-deterministic)finalize (deprecated)~ClassName() (deterministic, load-bearing for RAII)
Object memoryAlways on heapAlways on heapStack or heap — your choice
this referenceself, explicit first parameterthis, implicitthis (pointer), implicit
Data classes / POJOs@dataclass decoratorrecord (Java 14+)struct (same as class, default-public)

Python's "everything is an " is literal: even integers have methods ((5).bit_length()). Java separates primitives from objects. C++ gives you value-type objects (on the , fast) and /pointer-type objects (on the ).

QUICK CHECK

A performance-critical backend service written in C++ needs to allocate thousands of small configuration objects per second. A developer argues these objects should be created on the stack rather than the heap. Which language feature makes this possible in C++ but not in Python or Java?

Choose one answer

5. Tradeoffs & Decisions

  • vs. just a function + dict. If your "" has no methods and no invariants, a dictionary or tuple is fine. Classes earn their keep when you have invariants to enforce (balance ≥ 0) or a nontrivial API.
  • Public fields vs. getters/setters. Python culture prefers public fields with @property if you later need validation. Java culture historically uses getters/setters everywhere (IDEs generate them). Both work; the key is that callers go through a stable API.
  • vs. . creates tight coupling between parent and child. (holding another as a field) is looser. Reach for composition first; inheritance when you genuinely need "is-a" semantics and .
  • vs. objects. objects are safer across threads and easier to cache. objects are necessary when state genuinely changes. String is immutable in Python and Java; StringBuilder / list is mutable.
  • Value semantics vs. semantics. C++ Circle c(5); is a value — copy makes a new circle. Java/Python Circle c = new Circle(5); is always a — copying the shares the .

If you see a class with public fields, no methods, and no validation, it might as well be a dict / record / struct. You'd choose a full class when there are invariants to protect or meaningful behavior to attach.

QUICK CHECK

A junior developer on your team creates a UserProfile class with three public fields (name, email, age), no methods, and no validation logic. A code reviewer suggests replacing it with a plain dictionary. Which situation would best justify keeping it as a full class instead?

Choose one answer

6. Interview Cheat Sheet

  • A is a blueprint (fields + methods); an is a concrete instance produced from the blueprint.
  • Methods are functions with an implicit to the (self in Python, this in Java/C++).
  • Instance fields are per-object; (static) fields are shared by all instances.
  • Constructors run on creation and must leave the object in a valid state. Destructors (C++) run deterministically on exit; Python/Java rely on GC.
  • hides implementation behind a stable public API so you can change internals without breaking callers.
  • Python enforces access control by convention; Java and C++ enforce it at compile time.

Follow-ups:

  • "What's the difference between a class and an object?" — A class is the template; an object is one instantiation of it. Circle vs. c = Circle(5).
  • "What's self in Python?" — The object the method is being called on. Explicit first parameter by convention.
  • "When should you use a class instead of a dict?" — When you need to enforce invariants, attach behavior, or offer a stable API that can evolve without breaking callers.
Glossary History

Click dotted jargon to save explanations here.

Glossary History

Click dotted jargon to save explanations here.