8.1 Classes, Objects, and Encapsulation
Object-oriented programming models a program as cooperating objects. An object stores state and provides behavior. A class is the blueprint that describes what state each object owns and what operations are allowed on that state.
In C++, a class usually keeps data private and exposes a small public interface. This matters more in C++ than in many beginner languages because objects often manage resources: memory, files, handles, network connections, locks, and other things that must stay valid.
A first class
The BankAccount class below is the same kind of example used in the Java and Python OOP chapters, but the C++ details are stricter. Fields are usually data members, methods are member functions, and the access labels public: and private: control who can use each name.
#include <iostream>
#include <string>
class BankAccount {
public:
std::string owner;
std::string number;
double balance;
void deposit(double amount) {
balance += amount;
}
void withdraw(double amount) {
balance -= amount;
}
};
int main() {
BankAccount account;
account.owner = "Alice";
account.number = "6250941006528599";
account.balance = 50;
account.deposit(100);
std::cout << account.balance << std::endl;
return 0;
}This works, but it is too open. Any outside code can write account.balance = -1000000;. That means the object cannot protect its own rules.
Encapsulation
Encapsulation means keeping representation details inside the class and forcing outside code to use controlled operations. In C++, members of a class are private by default. Many teams still write private: explicitly so the design is easy to scan.
class BankAccount {
private:
std::string owner_;
std::string number_;
double balance_;
public:
BankAccount(std::string owner, std::string number, double balance)
: owner_(owner), number_(number), balance_(balance) {}
double balance() const {
return balance_;
}
bool deposit(double amount) {
if (amount <= 0) {
return false;
}
balance_ += amount;
return true;
}
bool withdraw(double amount) {
if (amount <= 0 || amount > balance_) {
return false;
}
balance_ -= amount;
return true;
}
};The outside code can ask for the balance and request a deposit or withdrawal, but it cannot directly assign to balance_. The class owns the invariant: "balance is changed only through validated operations."
Member functions, const, and this
A member function runs with a current object. Inside a member function, the hidden pointer this points to that object. You rarely need to write this explicitly, but it explains how account.deposit(100) knows which account to update.
bool deposit(double amount) {
if (amount <= 0) {
return false;
}
this->balance_ += amount;
return true;
}A member function marked const promises not to modify the object. This lets you call it on const objects and makes your interface easier to reason about.
double balance() const {
return balance_;
}
std::string owner() const {
return owner_;
}Use this rule of thumb: if a member function only reads state, mark it const. If it changes the object's state, leave off const and make the mutation clear in the function name.