Skip to content

Module 5 — Operators and Static Members

After this module your own types behave like built-in types where that genuinely helps — printable, comparable and sortable — and you can use class-level state without guessing what static does.


At a glance

Prerequisites Module 4
Estimated study time 8–10 hours
Lab Lab 5 — sortable, searchable, printable domain types
Exercises Three tiers — warm-up, core, challenge
Cognitive levels L2 Apply → L5 Design — exit level L4 Analyze
Self-assessment Module quiz

Why this module matters

You have a Book type. There are three things you will want constantly: to print it, to compare two of them, and to search or sort a collection of them. Without operator overloading, each of those becomes a named free function that every caller has to remember — printBook(b), booksEqual(a, b) — and none of them works with the standard library, which knows only about operators.

Overloading teaches your type the vocabulary C++ already speaks. std::cout << b then works, std::sort then works, and a == b reads like comparison of integers. That is the whole benefit, and it is a real one.

It is also the feature most often abused. You will learn where the line is: an overload that means what a reader expects is clarity; one that means something surprising is a bug with a friendly syntax.

The second half of the module, static, is small but frequently misunderstood. A static data member belongs to the class, not to each object, and that single fact explains both its usefulness (counters, shared configuration) and its pitfalls (unexpected sharing, and a definition rule that pre-C++17 code states awkwardly).


Learning objectives

By the end of this module you will be able to:

  1. Explain the purpose of operator overloading and state when overloading a given operator would be a mistake.
  2. List the operators that cannot be overloaded (::, ., .*, ?:, sizeof, typeid, alignof, and the named casts).
  3. State the rule that an overloaded operator must have at least one parameter of class or enumeration type.
  4. Choose correctly between a member function and a free function for a given operator, and explain why operator=, operator[], operator() and operator-> must be non-static members.
  5. Overload << as a free function taking std::ostream&, and return std::ostream& so that chaining works.
  6. Distinguish operator= (assignment to an existing object) from a copy constructor (creating a new one), and write an assignment operator that is correct under self-assignment.
  7. Provide operator== and operator< so a type works with standard algorithms, and explain why std::sort needs a strict weak ordering.
  8. Overload operator[] in both const and non-const forms.
  9. Write a functor with operator(), and explain how it relates to the lambdas of Module 14.
  10. Declare and define static data members and static member functions, including the C++17 inline static form.
  11. Explain why a static member function has no this pointer.

Core concepts

  • Operator function — a function named operator@ for some operator @. Overloading is just function definition with unusual syntax.
  • Member vs free operator — a member overload makes the left operand *this; a free overload names both operands. Symmetric operations, and any operation whose left operand is not your type, must be free.
  • operator<< for output — free, takes std::ostream& and returns it, so std::cout << a << b works. Usually needs friend access, or public getters.
  • operator>> for input — free, takes std::istream&, and must handle the failure state of the stream.
  • operator== and operator!= — equality. Implement == first; deriving != from == is both shorter and harder to get inconsistently wrong.
  • operator< — ordering. Required to be a strict weak ordering for the standard algorithms and containers to behave.
  • operator[] — element access. Provide the const and non-const pair so that const objects can be read but not written.
  • operator() — makes an object callable, like a function ("functor"). The basis of the predicates and comparators used throughout Module 14.
  • Conversion operator — operator T(); lets an object convert to another type. Powerful and easy to abuse; prefer a named function unless the conversion is obvious.
  • operator= — assignment. Must be a non-static member, must handle a = a, and its interaction with the copy constructor is the subject of Module 10.
  • Self-assignment — a = a. Harmless for simple types, fatal for classes that free a resource before copying the new one in.
  • static data member — one storage location per class, shared by every object. Must be defined exactly once outside the class, unless declared inline (C++17) or constexpr.
  • static member function — belongs to the class rather than an object, has no this, and therefore cannot be const and cannot touch non-static members.
  • Class-level state — for counters, shared configuration, and named constructors. A static factory function is the smallest useful design pattern in the course, and the seed of Module 15.

Module contents

Section What it contains
Introduction (this page) Overview, prerequisites, objectives, concept inventory
Concepts and explanations Overloading rules, member versus free, strict weak orderings, copy construction versus assignment, static members, the four operators to leave alone
Worked examples Four programs — a class-level counter, money that prints and sorts, a failed read that is not a rollback, and a measurement of what overloading && costs — plus a member-versus-free design table
Code examples examples/module-05/ — four programs, each with captured output that the build verifies
Misconceptions and mistakes Eight wrong mental models, ten symptoms, and four worked mistakes with their real compiler messages
Debugging Testing a comparator as a relation, the three failure classes, and the escalation ladder
Exercises Three tiers, including an invalid comparator to record and a link error to fix twice
Lab 5 The catalogue becomes sortable, searchable and printable — and the broken comparator is a deliverable
Challenge problems A type with three meaningful orders, an inconsistency hunt, and an identifier scheme for two translation units
Self-assessment Nine questions, including two predictions
Summary What must be retained, the terms to be able to define, and the checklist
Further reading Books and official documentation

What you can do after this module

  • Print any of your own types with std::cout << obj.
  • Sort and search a collection of your own types using the standard library.
  • Write an assignment operator that survives self-assignment.
  • Count how many objects of a class currently exist, using a static counter — and explain why that counter is not per-object.
  • Reject an overload proposal with a reason other than taste.

Where this is used later

  • operator< and == are prerequisites for using your types in std::map, std::set and the algorithms of Module 14.
  • operator= and self-assignment are the entry point to the Rule of Three in Module 10.
  • operator<< is reused for file output in Module 16, and for describing objects in tests.
  • operator() becomes lambdas and comparators in Module 14.
  • static factory functions grow into the factory pattern in Module 15.

Common mistakes to watch for

Symptom Cause
error: 'operator<<' must have an argument of class or enumerated type Both operands are built-in types. At least one must be one of yours
error: 'operator=' must be a non-static member function operator=, operator[], operator() and operator-> are declared as free functions
std::sort compiles but crashes or misbehaves operator< is not a strict weak ordering — for example it returns true for equal elements
error: 'operator<<' must take exactly one argument It was written as a member function. It usually needs to be free
A static member linker error: undefined reference to 'Book::count' The static member was declared but never defined outside the class (pre-C++17 style), or not declared inline/constexpr
error: invalid use of member in static member function A static function has no this, so it cannot touch non-static members
A counter jumps unexpectedly A copy was made. Count copies once constructors and the copy constructor are covered in Module 10

Skills checklist

Levels this module works at: [L2 Apply → L5 Design] — see How you will learn.

Tick an item only when the evidence exists:

  • [ ] I can overload ==, < and << so my own type works with standard algorithms — evidence: a sorted, printed vector of my own objects
  • [ ] I can say which operators must be members and which should be free, by naming the left operand — evidence: challenge X2's eight decisions, with reasons
  • [ ] I can write a valid comparator and test it as a relation — evidence: your duplicate-containing sort, plus the twenty-line property test
  • [ ] I can explain why an invalid comparator is undefined behaviour, and why a wrong order is the lucky outcome — evidence: your Lab 5 comparator note
  • [ ] I can tell copy construction from copy assignment on any line of code — evidence: the Track trace, predicted before it was run
  • [ ] I can declare, define and use a static data member, in either the classic or the C++17 form — evidence: the identifier counter, and your reason for the form you chose
  • [ ] I can explain why a static member function has no this — evidence: a written explanation with a checkable consequence (challenge X1)
  • [ ] I can refuse an overload proposal with a reason a reader can follow — evidence: the four operators you must not overload, with the guarantee each one would destroy

Suggested next step

Previous: Module 4 — Encapsulation · Next: Module 6 — Inheritance · All modules: Modules index

Module 6 assumes your types have real interfaces, honest comparisons and no contradiction between ==, < and printing — because it is about to build families of them. Lab 5's catalogue holds one kind of item; Lab 6 needs several, and the question of what a book, a journal and a DVD genuinely share is the first design question in this course with no single right answer.