Classes & Objects
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
- Model a
Clockclass with privatehoursandminutes, anaddMinutesmethod, and adisplaymethod. - Add a constructor to
Clockthat refuses invalid hour/minute values. - Write a
Counterclass withincrementandreset, and verify two counters stay independent. - Make
getValue() constand call it from both a normal and aconstobject.