Classes and Objects
Bundling data with the operations that act on it — the foundation of object-oriented programming.
A struct that holds data is useful. But often the data only makes
sense together with certain operations. A BankAccount is its
balance plus the rules for deposits and withdrawals. A Timer is
its start time plus the way you start, stop, and read it. Putting
data and behaviour together is the central idea of
object-oriented programming (OOP), and in C++ it's done with
classes.
From struct to class
Here is a struct holding bank account data:
struct BankAccount {
double balance;
};The trouble: any code anywhere can do account.balance = -1e9; —
nothing protects the rule that balances should not go negative.
A class lets us say: "the balance belongs to the account; outside code may only ask it to deposit or withdraw."
What changed:
- Access modifiers
public:andprivate:split the class into "the part the outside world sees" and "the part only methods may touch." - The data field is now named
balance_(trailing underscore is a common convention to mark members). - A constructor sets the field at creation time. We'll devote a whole chapter to constructors next.
- Methods (also called member functions) operate on the
object.
constafter the parameter list means "I promise not to modify the object."
Anatomy of a class
The public methods form the interface. The private fields are the implementation. The interface promises that the balance is always sensible; the implementation guards that promise.
Objects vs. classes
A class is a type — a description. An object is a value of that type — a specific instance.
BankAccount a(100.0); // a is an object
BankAccount b(500.0); // b is another, independent object
a.deposit(50.0); // affects only aEach object has its own copy of the private fields. Methods, on the other hand, exist once per class and operate on whichever object they were called on.
The hidden this pointer
When you call a.deposit(50.0), the compiler passes a's address
as a hidden first argument. Inside the method, the implicit pointer
this refers to the object:
void deposit(double amount) {
if (amount > 0) this->balance_ += amount; // same as balance_ += amount
}You rarely write this-> explicitly, but it's there. It's how the
method knows which account's balance to change.
Constness on methods
Methods marked const may be called on const objects and may not
modify the object. Methods without const may modify it.
class Timer {
public:
void start(); // modifies — non-const
double seconds() const; // observes — const
};Mark every method that doesn't change state as const. This is one
of the most useful disciplines in C++.
A small but complete example
The class hides its fields, exposes a small clear interface, and keeps an obvious invariant ("count_ only ever goes up by one").
Challenge
Complete the Counter class so that it supports tick() (increments by 1), reset() (sets back to 0), and value() const (returns the current count). The main function is wired to call them and print 2 0 if your class works correctly.
Test your understanding
What is the difference between a class and an object?
They are the same thing.
A class is a type — a blueprint describing data and operations. An object is an instance of that type, with its own copy of the data.
An object is a class with no methods.
A class can only exist once per program.
Why mark a method const?
It makes the method run faster.
It is required by the compiler.
It documents and enforces that the method does not modify the object, allowing it to be called on const instances and helping readers reason about behaviour.
It hides the method from outside code.
Next: why we hide fields — encapsulation and the idea of an invariant.