Classes, RAII & the Rule of Five
C++ OOP carries the four pillars, plus a discipline no managed language needs: because objects own resources, C++ ties cleanup to their lifetime through RAII.
Classes & Encapsulation
A class bundles data and behavior, with private members hidden and public ones exposed. (A struct is identical but defaults to public.)
class BankAccount { private: double balance = 0; // hidden state public: void deposit(double amount) { if (amount > 0) balance += amount; } double getBalance() const { // const method — promises not to modify return balance; } }; BankAccount acc; acc.deposit(100); acc.getBalance(); // 100 // acc.balance = -50; // ERROR — balance is private
const when they don't modify the object. It lets them be called on const objects and documents intent — the compiler enforces the promise.Constructors, Destructors & RAII
RAII (Resource Acquisition Is Initialization) is the single most important C++ idea. An object grabs a resource in its constructor and releases it in its destructor, which the compiler calls automatically when the object goes out of scope. Cleanup becomes guaranteed, not something you remember to do.
class File { FILE* handle; public: File(const char* name) { // constructor — acquire handle = fopen(name, "r"); } ~File() { // destructor — release, called automatically if (handle) fclose(handle); } }; void use() { File f("data.txt"); // opens the file // ... work with f ... } // f's destructor runs HERE — file closed automatically, even on exception
delete.The Rule of Three / Five
If a class manages a resource and needs a custom destructor, it almost certainly also needs a custom copy constructor and copy assignment (the Rule of Three). Modern C++ adds the move constructor and move assignment (making it Five).
| Special Member | When it runs |
|---|---|
Destructor ~T() | Object is destroyed |
Copy constructor T(const T&) | T b = a; |
Copy assignment operator=(const T&) | b = a; |
Move constructor T(T&&) | T b = std::move(a); |
Move assignment operator=(T&&) | b = std::move(a); |
vector or unique_ptr) and need none of these five. Then the compiler-generated defaults are correct and you write nothing.Inheritance & virtual
C++ supports inheritance and polymorphism, but polymorphism is opt-in: a base method must be marked virtual for a derived override to be called through a base pointer or reference.
class Animal { public: virtual std::string speak() const { return "..."; } virtual ~Animal() = default; // virtual destructor — essential for base classes }; class Dog : public Animal { public: std::string speak() const override { return "Woof"; } }; Animal* a = new Dog(); a->speak(); // "Woof" — virtual dispatch to Dog delete a; // virtual destructor ensures Dog's destructor runs too
virtual, calling a->speak() runs Animal's version, not Dog's. And a base class deleted through a base pointer must have a virtual destructor, or the derived part leaks.