← Back to Programming

Classes and the C++ type system

C++ classes give you full control over how objects are created, copied, moved, and destroyed. Templates let you write code that works for any type with no run-time cost.

Classes and structs

class Point { public: Point(double x, double y) : x_(x), y_(y) {} double x() const { return x_; } private: double x_, y_; };. The constructor uses a member initialiser list. A const member function promises not to change the object. struct is identical to class except members are public by default, conventionally used for simple data.

Destructors

A destructor, written ~ClassName(), runs automatically when an object is destroyed, such as when it goes out of scope. It releases resources the object owns, which is how RAII works. Standard containers and smart pointers already have correct destructors, so classes built from them often need no custom destructor.

Copy and move

Objects can be copied, duplicating their contents, or moved, transferring resources from an object that is about to be discarded, which is much cheaper for large data. C++11 introduced move semantics; std::move marks an object as movable. The 'rule of zero' advises designing classes so the compiler-generated copy, move, and destructor operations are correct.

Inheritance and virtual functions

class Circle : public Shape inherits from Shape. For run-time polymorphism, a base class declares virtual functions: virtual double area() const = 0; makes Shape abstract. Derived classes override them, marked override. A base class used polymorphically needs a virtual destructor so derived objects are destroyed correctly.

Operator overloading

C++ lets classes define operators: Point operator+(const Point& a, const Point& b) lets you write p1 + p2. Overloading suits types where the operator's meaning is natural, such as vectors, complex numbers, and matrices. std::string uses + for joining and == for comparison through overloading.

Templates

Templates write generic code: template <typename T> T maxOf(T a, T b) { return a > b ? a : b; } works for ints, doubles, and strings. The compiler generates a specialised version for each type used, so there is no run-time overhead. The standard library's containers, such as std::vector<T>, are templates. C++20 concepts constrain what types a template accepts.

The Standard Template Library

The STL provides containers (vector, map, unordered_map, set), iterators that step through them, and algorithms such as std::sort, std::find, and std::accumulate that work on any container through iterators. Lambdas customise algorithms: std::sort(v.begin(), v.end(), [](int a, int b) { return a > b; }) sorts in descending order.

Worked example

std::vector<int> v{5, 2, 9, 1}; std::sort(v.begin(), v.end()); gives 1, 2, 5, 9. int total = std::accumulate(v.begin(), v.end(), 0); gives 17. auto it = std::find(v.begin(), v.end(), 9); finds 9 at position 3, computed as it - v.begin(). These generic algorithms work equally on other containers that provide suitable iterators.

Key takeaways

Classes have constructors with initialiser lists, const member functions, and access control; structs default to public. Destructors release resources automatically. Move semantics transfer resources cheaply; the rule of zero favours compiler-generated operations. Virtual functions enable run-time polymorphism; pure virtual functions make abstract classes; polymorphic bases need virtual destructors. Operators can be overloaded. Templates give zero-overhead generic code; concepts constrain them. The STL combines containers, iterators, and algorithms.

Flashcard

Member initialiser list

Initialises fields in a constructor

: x_(x).

Check your understanding

Why does a C++ base class used through pointers to derived objects need a virtual destructor?

← Previous lesson Next lesson →