Classes & Objects
From Scattered Data to Organized Objects
Imagine you're building a banking app. You could track each customer with separate variables β balance1, name1, balance2, name2 β but that gets messy fast. What you really want is a BankAccount blueprint that bundles the data (balance, name) with the operations (deposit, withdraw) into one clean package.
That blueprint is a class. Each account you create from it is an object (or instance). The class defines the rules; the objects live by them.
class vs struct
In C++, class and struct are almost identical. The only difference is the default access level:
structβ members are public by defaultclassβ members are private by default
By convention, use struct for simple data bundles (like a Point with x and y) and class for anything with behavior and invariants.
struct vs class β The Only Real Difference
Constructors β Building the Object Right
A constructor is a special function that runs when an object is created. Its job is to put the object into a valid state from the very beginning. No half-initialized objects floating around.
C++ gives you several constructor flavors:
- Default constructor β no parameters, creates a sensible default
- Parameterized constructor β takes arguments to initialize with specific values
- Member initializer list β initializes members before the constructor body runs (faster, and required for const/reference members)
BankAccount β A Complete Class
: owner(name), balance(initial) directly initializes each member. Assigning in the body (owner = name;) first default-constructs the member, then assigns β doing double work. For const and reference members, initializer lists are required.Access Modifiers β Controlling the Doors
Every member of a class has an access level:
- public β anyone can access it. This is the interface you expose to the world.
- private β only the class itself can access it. This is for internal data and helper functions.
- protected β the class and its derived classes (children) can access it. We'll see this more in inheritance.
The golden rule: make data private and provide public methods to interact with it. This is called encapsulation β hiding the messy internals behind a clean interface.
The this Pointer
Inside any non-static method, this is a pointer to the current object. You rarely need it explicitly, but it's useful when a parameter name shadows a member name, or when you want to return the object itself for method chaining.
The this Pointer & Method Chaining
const Methods β The Read-Only Promise
Marking a method const tells the compiler: "this method will NOT modify any member variables." This is crucial because it allows you to call the method on const objects and const references. If you have a const BankAccount&, you can call getBalance() (const) but not deposit() (non-const).
Destructors β Cleaning Up
A destructor runs automatically when an object is destroyed (goes out of scope, is deleted, etc.). Its name is ~ClassName(). For simple classes, the compiler-generated destructor is fine. You write your own when the class manages resources like heap memory, file handles, or network connections.