Skip to content

Intermediate Project 9 — Contact Book

Difficulty: Intermediate · Estimated effort: 12–16 hours · Prerequisites: Module 13 — Exception Handling, Module 14 — The STL with OOP, Module 5 — Operators and Static Members · Combines: persistence with a real round trip, indexed search, editing under an invariant, merge and deduplicate

This is one of the designated integration projects. It must use, explicitly and in writing: multiple classes · relationships between classes · encapsulation · inheritance or composition · polymorphism · the STL · exception handling.

No complete solution is provided. "Search" is where the design decisions concentrate, and they are yours to make.


1. Scenario

A department keeps a shared contact book of suppliers, staff and students. It holds names, several phone numbers and email addresses per person, a category, and a note. Entries are added and edited by hand, the file is sometimes hand-edited too, and duplicates creep in when the same person is entered twice with a different spelling.

The book must merge cleanly from two devices, which means deciding what "the same contact" means and making that decision survive a round trip.


2. Problem statement

Build a contact book: contacts with several contact methods each, categorised, searchable by name and by method, loaded from and saved to a documented text format, with duplicate detection on merge and precise, line-numbered errors for a bad file.


3. User requirements

  • [ ] Add, edit and remove contacts; changes are validated before they land.
  • [ ] Attach zero or more phone numbers and emails to a contact.
  • [ ] Search by partial name, ignoring case, and by a contact method.
  • [ ] List contacts by category.
  • [ ] Merge another book file in, reporting duplicates found and how they were resolved.
  • [ ] Save and reload, with the file readable and editable by hand.

4. Functional requirements

  • [ ] Contact with a name, a category and a collection of contact methods.
  • [ ] A ContactMethod abstraction or a value type with a kind — choose and justify; this is the polymorphism decision in the project.
  • [ ] A Book owning contacts, with add, edit, remove and search.
  • [ ] A documented file format supporting several methods per contact and an escape for the separator.
  • [ ] Duplicate detection with a documented identity rule and a documented resolution rule.
  • [ ] Errors for a malformed line, an empty name and an unknown category, each naming context.
  • [ ] A failed merge leaves the book exactly as it was.

5. Non-functional requirements

  • [ ] Search is not a full comparison of every field of every contact if you can index it — and if you do index it, you measure the difference and report it.
  • [ ] Edits that would create an invalid contact are refused atomically.
  • [ ] Round trip preserves names with the separator character in them.
  • [ ] Contacts with zero methods are legal, and the format can express them.
  • [ ] Builds warning-free with g++ -std=c++17 -Wall -Wextra -Werror.

6. Suggested features

  • A per-contact change history of the last few edits, capped and explained.
  • Fuzzy duplicate detection (case- and space-insensitive names), with a false-positive example you accept.
  • Import and export through the same interface with two formats.
  • A Book view filtered by category that references rather than copies.

7. OOP concepts involved

Concept Required Where it appears
Multiple classes yes Contact, contact methods, Book, search index, merge policy, error types
Relationships yes Book ◆ contacts; contact ◆ its methods; a search view ──> contacts it does not own
Encapsulation yes A contact cannot exist without a name; methods cannot be edited without revalidation
Inheritance or composition yes Method kinds as a hierarchy, or as a tagged value — the same decision the quiz engine faces, argued here
Polymorphism yes At least one operation dispatching on method kind (validation, normalisation or display)
The STL yes std::vector for order, std::map/std::set for indexes, algorithms for search and merge
Exception handling yes Malformed files and invalid edits throw distinct types; a failed merge rolls back

8. Suggested design considerations

Define identity before writing merge. "Same person" might mean the same email, the same name and category, or the same phone number. Each choice has a failure mode, and the merge test is built from your rule. Write the rule down as a sentence and then implement that sentence.

Index, then justify. If you keep a case-folded name index, a measurement of search over ten thousand contacts is worth more than the assertion that it must be faster. If you do not index, say what the input size would have to be to make you.

Roll back the merge. Merging two books can fail halfway — a bad line, a conflicting edit. Build the result in a local book and move it into place, then prove with a test that the original is untouched after a failure.

Hand-editable means the format documents its own escaping. If a name contains the field separator, the file must say so unambiguously. Choose an escape rule and test it with a name containing it.


9. Minimum viable version

Contact with a name and one method, a Book with add/remove/list, and save/load for the simple case. No search index, no merge.


10. Intermediate extension

Add multiple methods per contact, the category filter, case-insensitive partial-name search and the escape rule, then verify that a round trip preserves a name containing the separator and a contact with zero methods.


11. Advanced extension

Add the merge with duplicate detection and rollback, plus an indexed search with a measured comparison against the linear version. Then export in a second format behind the same interface and record which files the change touched.


12. Testing checklist

  • [ ] A contact with no methods round-trips and is listed
  • [ ] A name containing the separator round-trips through the documented escape
  • [ ] Search is case-insensitive and matches substrings, including at the start and end
  • [ ] Categories are listed in a documented order and an unknown category is refused
  • [ ] Editing a name to empty is refused and changes nothing
  • [ ] Removing a contact leaves the rest untouched and their order preserved
  • [ ] Merging a book with itself reports every contact as a duplicate and changes nothing
  • [ ] Merging a book with one bad line fails entirely and leaves the target book unchanged
  • [ ] Duplicate resolution follows the documented rule for each tested combination
  • [ ] An indexed search and a linear search return the same set for ten test queries
  • [ ] Save → load → save produces identical files

13. Documentation checklist

  • [ ] The identity rule for a contact, in one sentence
  • [ ] The duplicate-resolution rules, in a table
  • [ ] The file format, with escaping specified and an awkward example
  • [ ] The measurement table for search, if you indexed
  • [ ] One note answering: value type or hierarchy for contact methods, and why?

14. Self-evaluation rubric

Criterion Excellent looks like Weight
Identity and merge Identity defined, duplicates resolved by rule, rollback proven 25%
Format design Hand-editable, escaped, versioned, round-trip tested on awkward data 25%
Search Correct and, if indexed, measurably faster with numbers 15%
Interface Edits validated atomically; views reference instead of copying 15%
Failure handling Bad files and bad edits refused with context, nothing left half-done 10%
Documentation Rules, format and evidence written down 10%

Related: Intermediate projects · Project roadmap · All projects · Module 14 — The STL with OOP