Classes & Objects

Scope: A class bundles data and the functions that operate on it into one unit — the heart of object-oriented programming. This lesson covers defining classes, constructors, access control, encapsulation, and the special roles of this and const.

Defining a class

A class is a blueprint. It declares data members (the state) and methods (member functions that work with that state). The blueprint itself takes no space; space is reserved when you create objects, the living instances.

Data members and methods

#include <string>

class BankAccount {
public:                                  // accessible from outside
    void deposit(double amount) {
        balance += amount;               // method reads/writes members
    }

    double getBalance() const {          // const: promises not to modify
        return balance;
    }

private:                                 // hidden from outside
    std::string owner;
    double balance = 0.0;
};

Members declared after public: are reachable by any code; members after private: only by the class's own methods. This split is the basis of encapsulation, below.

Access control

The three access levels are public (everyone), protected (this class and its descendants — the inheritance lesson uses it), and private (only this class). The default for class is private.

BankAccount account;
account.deposit(100.0);            // public method — OK
// account.balance = 999;          // error: balance is private

Creating objects

An object is a concrete instance of the class. You create one exactly like a variable, and each object carries its own copy of the data members.

BankAccount a;      // object a — balance 0.0, owner ""
BankAccount b;      // object b — completely independent state
a.deposit(50.0);
// b is still at 0.0

Constructors

A constructor is a special method with the class's own name: it runs when an object is created and sets the initial state. Constructors can take parameters and can be overloaded.

class BankAccount {
public:
    BankAccount(std::string owner, double opening = 0.0)
        : owner(owner), balance(opening) {   // member initializer list
    }
    // ... deposit(), getBalance() as before ...
private:
    std::string owner;
    double balance;
};

BankAccount account{"Ada", 100.0};   // constructor call (braces)

The initializer list (the : owner(owner), balance(opening) part) sets members before the body runs — prefer it over assignments inside the body: it is faster and works for members that cannot be reassigned.

Encapsulation

Encapsulation means hiding the internal state behind a public interface. Outside code can only interact through methods, so the class can enforce its own rules:

class Thermal {
public:
    void setTemperature(double t) {
        if (t < -50.0 || t > 150.0) return;   // reject nonsense
        temperature = t;
    }
    double getTemperature() const { return temperature; }
private:
    double temperature = 20.0;   // the only way in is setTemperature()
};

The payoff: callers cannot corrupt the state, and the class can change its internals later without breaking them. The C++ Core Guidelines call this "make interfaces explicit and stable".

this & const members

Inside a method, this is a pointer to the object being operated on. You rarely need it explicitly — the compiler resolves member names — but it is required when a parameter shadows a member:

void setOwner(std::string owner) {
    this->owner = owner;     // this->owner is the member; owner is the parameter
}

Mark methods that do not modify the object as const (see getBalance() const). The compiler then refuses to call them on a const object, and readers instantly know which calls are safe.

Copying objects

Copying a class with only plain members is automatic and correct — every member is copied. The trouble starts when a class owns resources (memory, files, threads): a plain copy duplicates the handle, not the resource, producing two objects that free the same thing twice.

BankAccount original{"Bob", 10.0};
BankAccount copy = original;   // automatic copy — fine for plain members

The memory lesson introduces smart pointers and the "rule of zero/three/five" that governs resource-owning classes.

Practice

  1. Model a Clock class with private hours and minutes, an addMinutes method, and a display method.
  2. Add a constructor to Clock that refuses invalid hour/minute values.
  3. Write a Counter class with increment and reset, and verify two counters stay independent.
  4. Make getValue() const and call it from both a normal and a const object.