Notifications

No notifications

/Phase 2

Classes & Objects

Bundling Data with Behaviour 🧱

A class is a blueprint that bundles data (members) and functions (methods) that act on it. An object is an instance.

class Point {
public:
    double x, y;

Point(double x, double y) : x(x), y(y) {} // constructor

double distanceTo(const Point& other) const { // method double dx = x - other.x; double dy = y - other.y; return sqrt(dx*dx + dy*dy); } };

int main() { Point p{3, 4}; Point q{0, 0}; cout << p.distanceTo(q); // 5 }

Access Specifiers

KeywordVisible to
publicEveryone
privateOnly this class (default for class)
protectedThis class and derived classes

struct vs class

In C++, struct and class are nearly identical — only the default access differs:

Default access
structpublic
classprivate

Convention: use struct for plain data bags, class when you have invariants/encapsulation.

Constructors & Destructors

class File {
    FILE* fp;
public:
    File(const string& path) { fp = fopen(path.c_str(), "r"); }   // constructor
    ~File()                  { if (fp) fclose(fp); }               // destructor — RAII!
};

When a File object goes out of scope, its destructor runs automatically. No manual cleanup needed. This is RAII — the soul of modern C++.

On this page

Detailed Theory

Classes are how you turn raw data into safe, reusable building blocks. Modern C++ relies on classes for everything from STL containers to smart pointers.

Anatomy of a Class

class BankAccount {
private:
    string owner;       // member data (private = encapsulated)
    double balance;

public: BankAccount(string owner, double initial) // constructor : owner(std::move(owner)), balance(initial) {}

void deposit(double amount) { // method balance += amount; }

bool withdraw(double amount) { if (amount > balance) return false; balance -= amount; return true; }

double getBalance() const { // const method (read-only) return balance; } };

Member Initialiser List

Always prefer the initialiser list (after :) over assigning inside the body:

class Rect {
    int w, h;
public:
    Rect(int w, int h) : w(w), h(h) {}     // ✅ direct init
    // not:
    // Rect(int W, int H) { w = W; h = H; }   // ❌ default-constructs then assigns
};

Required for const, references, and non-default-constructible members.

this Pointer

Inside a non-static method, this is a pointer to the current object:

class Foo {
    int x;
public:
    Foo& set(int x) {
        this->x = x;       // disambiguate parameter from member
        return *this;       // chaining: foo.set(1).set(2)
    }
};

const Methods

A method declared const promises not to modify the object's data. Const objects can call only const methods.

class Circle {
    double r;
public:
    double area() const { return 3.14159 * r * r; }  // doesn't change r
    void scale(double f) { r *= f; }                 // not const — modifies r
};

const Circle c{5}; c.area(); // ✅ ok c.scale(2); // ❌ compile error — c is const

> Mark every method that doesn't modify state as const. It enables read-only usage and helps the compiler optimise.

Constructors

KindWhen
DefaultFoo() — no args
ParameterisedFoo(int x)
CopyFoo(const Foo& other)
MoveFoo(Foo&& other) (C++11)
DelegatingFoo() : Foo(0) {}

class Point {
    int x, y;
public:
    Point() : Point(0, 0) {}                  // delegates
    Point(int x, int y) : x(x), y(y) {}
    Point(const Point& other) = default;       // explicit default
};

Destructor

Runs automatically when the object's lifetime ends:

class Buffer {
    int* data;
public:
    Buffer(size_t n) : data(new int[n]) {}
    ~Buffer() { delete[] data; }              // RAII: cleanup is guaranteed
};

This is RAII (Resource Acquisition Is Initialisation) — own resources in objects so destructors clean up. Used by:

  • std::vector (frees the array)
  • std::string (frees the buffer)
  • std::unique_ptr (frees the pointee)
  • std::lock_guard (releases the mutex)

Encapsulation: Public Interface, Private Data

class Counter {
    int count = 0;          // private — outside code can't touch
public:
    void inc()       { ++count; }
    int  value() const { return count; }
};

Counter c; c.inc(); cout << c.value(); // c.count = 999; // ❌ compile error — count is private

Private data + public methods = you control how the object is used.

Constructors That Take One Arg — Beware Implicit Conversion

class Money { public: Money(double amount); };
Money m = 19.99;       // ⚠️ implicit conversion from double — surprising

Mark single-argument constructors explicit to forbid this:

explicit Money(double amount);
Money m = 19.99;       // ❌ now an error
Money m{19.99};        // ✅ explicit construction

Static Members

Belong to the class, not any instance:

class Logger {
    static int count;
public:
    Logger()  { ++count; }
    static int total() { return count; }
};
int Logger::count = 0;     // definition, in a .cpp file

cout << Logger::total();

Friends

friend lets a function or another class access private members. Use sparingly — usually for stream operators:

class Vec2 {
    double x, y;
public:
    Vec2(double x, double y) : x(x), y(y) {}
    friend ostream& operator<<(ostream& os, const Vec2& v);
};
ostream& operator<<(ostream& os, const Vec2& v) {
    return os << "(" << v.x << "," << v.y << ")";
}

Operator Overloading (Preview)

Classes can define what +, -, ==, etc. mean:

class Vec2 { /*...*/
    Vec2 operator+(const Vec2& o) const { return {x + o.x, y + o.y}; }
    bool operator==(const Vec2& o) const { return x == o.x && y == o.y; }
};
Vec2 a{1,2}, b{3,4};
Vec2 c = a + b;      // calls operator+

Rule of Zero / Three / Five

If your class doesn't manage a raw resource, don't write any of: copy ctor, copy assignment, move ctor, move assignment, destructor. The compiler-generated ones are correct (Rule of Zero).

If your class does own a raw resource, you typically need all five. Modern C++ avoids this by wrapping resources in unique_ptr, vector, string, etc.

Cheat-Sheet

NeedCode
Plain datastruct Point { int x, y; };
Encapsulatedclass Foo { private: ... public: ... };
Constructor (init list)Foo(int x) : x_(x) {}
Read-only methodint get() const { ... }
Cleanupdestructor ~Foo() { ... }
Forbid implicit convexplicit Foo(int);
Class-wide datastatic int count;
Default copy/moveFoo(const Foo&) = default;
Forbid copyFoo(const Foo&) = delete;

You now understand the heart of C++ OOP. Phase 3 dives into inheritance, polymorphism, smart pointers, and templates — built on exactly these foundations.