Skip to content

Module 5 — Summary

The essentials

  • Operators are how your type joins C++ instead of living beside it. With < and ==, the library's algorithms work on your type; with <<, it prints anywhere. That is a change in capability, not a syntax preference.
  • At least one operand must be a class or enumeration type, and the meaning of built-in types can never change. ::, ., .*, ?: and the named casts cannot be overloaded at all, because they are how names and control flow are resolved.
  • =, [], (), -> and conversions must be members. Streams, arithmetic and symmetric comparisons should be free, because the left operand is not your type. The test is one question: what is the left operand?
  • << returns the stream, so that std::cout << a << b works; it takes std::ostream& first, and usually needs no friend if the type has an honest accessor.
  • Write == and < by hand and derive the other four from them. Six independent definitions eventually disagree; two definitions and four derivations cannot drift. In C++17, != is a separate function that must be written.
  • A comparator must be a strict weak ordering: irreflexive, asymmetric, transitive. If it is not, ordered algorithms are undefined behaviour — they may work and they may not, and a wrong order is the lucky outcome. Test the relation with a twenty-line property test and a duplicate in the sample.
  • Book b = a; is initialisation, not assignment. The = sign is not the assignment operator there; the question that always answers it is did the object already exist?
  • static has three distinct meanings: a data member is class-level state, one per class; a local variable lives until exit and is initialised once; a free function has internal linkage. Learn them as three facts, not one.
  • A static data member is declared in the class and defined once outside it, or written inline static (C++17). Forgetting produces a link error naming the member, not a compile error — the compiler was satisfied.
  • A static member function has no this, so it cannot touch instance data and cannot be const. That is exactly why it is the home of class-level facts and named constructors.
  • Leave &&, ||, , and & alone. Each carries a guarantee — short-circuiting, sequencing, taking an address — that a user-defined operator, being an ordinary function call, silently destroys. The loss is measurable: examples/module-05/04-operators-not-to-overload/main.cpp counts it.
  • Consistency is the requirement. ==, < and printing must agree about what the type is, or the standard library's promises become your bugs.

The one-sentence version

Give your type the fewest operators that let it participate in the rest of C++, make them mean what a reader already expects, keep == and < consistent with each other, and remember that static belongs to the class rather than to any object.

Terms you must now be able to define

Operator function · overload resolution for operators · member versus free operator · operator<< and chaining · symmetric operator · conversion operator · explicit operator bool · strict weak ordering · irreflexive · asymmetric · transitive · undefined behaviour from a bad comparator · short-circuiting (and how overloading && destroys it) · copy construction versus copy assignment · self-assignment · static data member · static member function · static local · inline static · class-level state · named constructor

See the glossary. Two matter more than the rest for what follows: strict weak ordering (Module 14 uses every container and algorithm that depends on it) and copy construction versus assignment (Module 10 is the consequences, and Module 11 is the cure).

The habit to keep

Before writing an operator, name its left operand. If the answer is not your type, the operator cannot be a member — and if the answer is a stream, the shape of the free function follows immediately. Three seconds, and it prevents the two errors this module spends the most time on.

Second habit, once per module: test the relation, not the algorithm. An assert(!(a < a)) costs one line and finds what a sort hides.

Before you move on

  • [ ] Warm-up and core exercises attempted, with results checked
  • [ ] Lab 5 builds with no warnings, and its comparator note records a run, not a description
  • [ ] The property test for operator< passes with duplicates in the sample
  • [ ] Your type's ==, < and printing agree, and the sentence defining identity is written in a comment
  • [ ] Every static data member is defined once, and you can say which C++17 form you used and why
  • [ ] You can list the four operators you must not overload, from memory
  • [ ] Self-assessment ≥ 80%, and question 8's answer states the honest position on undefined behaviour
  • [ ] At least one challenge problem attempted, with the rubric applied
  • [ ] The skills checklist on the module page ticked with evidence

Further reading

  • The C++ Programming Language (4th ed.), chapter 18 — the definitive treatment of operator overloading, including which operators must be members and why the language's conversion rules make symmetry matter.
  • Effective C++ (3rd ed.), Items 10 and 11 — the copy functions, and the operator= that must survive self-assignment. Items 18–19 on interfaces that are hard to misuse explain this module's member-versus-free rules from the design side.
  • The C++ Standard Library (2nd ed.), the chapter on algorithms — what std::sort actually requires of your type, and why a comparator is a relation rather than a function that returns a bool.
  • C++ Core Guidelines — C.160 (don't define operators unless they mean the obvious thing), C.161 (prefer free operators for symmetric operations), C.86 (make same-argument-type operators symmetric), C.60–C.63 (the copy and move operations). About a dozen short rules; this module is most of their content.
  • The C++ Standard, [alg.sorting] — the clause that defines strict weak ordering. Worth reading once in the original, because it is the reason "it worked on my machine" is not an argument.

See Further Reading for editions and why these are the right ones.


Next: Module 6 — Inheritance. Module 6 builds families of types out of the types you have just made comparable, printable and sortable — and the first design question it asks has no single right answer: what do a book, a journal and a DVD genuinely share?