Skip to content

Module 2 — Self-Assessment

Nine questions. Answer them closed-book, in writing, in about twenty minutes. The writing matters: recognising an answer is not the same as producing one, and only one of those is what an exam, an interview or a review will ask for.

There is a quiz with the same purpose in Quizzes. This page is the one to use immediately after finishing the module, because it names the section to re-read for every question you miss.


The questions

  1. What is the difference between a class and an object? Give one example of each from the course's library system.

  2. State the only language difference between class and struct. Which would you use for a Money type that must never hold a negative amount, and why?

  3. Predict, then check. What does this print, and why?

#include <iostream>

class Counter {
public:
    int value() const { return value_; }
    void bump() { ++value_; }
private:
    int value_ = 0;
};

void twice(Counter counter) {
    counter.bump();
    counter.bump();
}

int main() {
    Counter c;
    twice(c);
    c.bump();
    std::cout << c.value() << '\n';
}
  1. Why does this fail to compile, and what are the two legitimate fixes?
error: passing 'const Book' as 'this' argument discards qualifiers
  1. In a two-file program, explain the difference between what the compiler checks and what the linker checks, and say which one reports undefined reference to Book::describe() const.

  2. Why is #pragma once — or an include guard — necessary in a header? What is the error without it?

  3. Name the two situations in which this is needed explicitly, and say what *this means in each.

  4. Member enforces a limit of three borrowed items. A colleague proposes moving the check into the code that calls borrow(), "so the class can be reused with a different limit". Give one reason the proposal is defensible and one reason it is dangerous, and say which you would choose.

  5. A class has an invariant, and a private data member to go with it. A second programmer asks you to add a getter and a setter for it. Describe the question you would ask before answering, and how each possible answer changes your response.


Answers

1. A class is a type — a description of data and operations; an object is one instance of it. class Book describes every book; Book primer(1001, "C++ Primer") creates one. Two objects of one class have independent data, which is why correcting the page count of one book leaves the other alone (examples/module-02/01-book-class/main.cpp).

2. Default member access (public for struct, private for class; the same difference exists for the default inheritance mode). Money should be a class: it has a rule, and the rule needs an enforced place. A struct with long long paisa; public cannot prevent m.paisa = -1; — and a Money type whose invariant is only in the author's memory is a long long with a longer name.

3. It prints 1. twice takes its parameter by value, so it operates on a copy which is destroyed on return — the two bump() calls are visible only inside the function. c.bump() then takes the object to 1. Two ideas are being tested: a class-type parameter is a copy (unlike Java or C#, where it would be a reference), and member functions called on the copy do not affect the original. This is the point of M7 in Misconceptions, and the mechanism is Module 3's.

4. Inside a const Book, this is a const Book*, so a member function that might modify the object cannot be called. The two legitimate fixes: (a) mark the function const, if it genuinely does not modify the object — the compiler is telling the truth and this is the usual answer; (b) change the parameter so it is not const, if the function really does need to modify. const_cast is a third option and is almost always a bug: it converts a compile-time error into undefined behaviour at run time.

5. The compiler translates each .cpp file separately: it checks syntax, types and names, and it needs only a declaration to accept a call. Every name also needs exactly one definition, and only the linker checks that, once, at the end. So it reports undefined reference: the code that used the function compiled happily against a promise that no .cpp kept.

6. #include is a paste operation, so a header included twice — directly and through another header — pastes the class definition into the same translation unit twice. Without a guard the compiler reports redefinition of 'class Book'. The guard tells the preprocessor to paste it only once.

7. (a) When a name hides a member: a constructor parameter called id hides a member called id, so id = id; assigns the parameter to itself; this->id = id; resolves it. (b) When returning the object itself: return *this; — returning the object, not a pointer to it — is what lets calls chain, because the caller receives a reference to this same object rather than a copy.

8. Defensible: a fixed limit inside Member is a policy, and policy in a class makes the class hard to reuse with a different limit — the caller may be the only place that knows what the limit should be. Dangerous: the limit then has to be known at every call site, so it exists in as many places as there are callers, and any caller that forgets it silently breaks the invariant. The design answer is neither: keep the enforcement in the class and make the limit a parameter — Member(name, limit) — so the policy varies while the enforcement stays in one place. That is dependency injection, and Module 15 formalises it.

9. The question to ask first: what would the caller do with the value? If they can answer it with an operation the class could provide — canAfford(price) rather than getBalance(), hasId(id) rather than getId() — the accessor is the wrong tool and the class should grow the operation instead. If the value is genuinely read-only information (Book::id()), a getter is fine and needs no setter. If the caller needs to change it, ask what operation of the system that change represents; that operation is what belongs in the class. And if the honest answer is "I do not know yet", that is a reason to leave it private until you do, not to publish it and find out later — which is the whole of Module 4 in one paragraph.


Marking yourself

One mark per question; give yourself a mark only if your written answer names the mechanism, not merely the effect. "It's because of const" is not a mark for question 4; "this is a const Book* inside a const member function" is.

Score What it means What to do
9 You have Module 2. Move to Lab 2 if you have not finished it, then Module 3
7–8 Solid, with one or two conceptual gaps Re-read the section for each miss and re-answer those questions tomorrow — not today
5–6 The syntax is there; the model is not yet Re-read §§5–7 and §9 of Concepts, then redo warm-up W2 and W3
0–4 The module needs a second pass Start again from §1, and type out every program in Worked examples by hand. Do not skip to Module 3: every module after this one assumes you can read a class

Which section to re-read, by question:

Missed question Re-read
1, 2 Concepts §1–2
3 Concepts §9, then Module 3
4 Concepts §7 and Debugging, Diagnosis B
5, 6 Concepts §8 and Debugging, Diagnosis A
7 Concepts §6
8, 9 Misconceptions M2 and M3 — both are answered properly in Module 4

Re-test schedule

Handing a concept once is storage, not learning. Three short re-tests, ten minutes each:

When Do what
Tomorrow Re-answer only the questions you missed, from memory
In a week Answer all nine again, then compare with today's sheet. Was anything forgotten that you had answered correctly? That is the interesting column
In a month One question, answered in code rather than prose: write the smallest program that demonstrates each mechanism you were asked to explain

A month from now you will have finished Modules 3, 4 and 5, and this sheet will read differently — that is expected. Keep it. The questions you got wrong today are the ones your later self finds trivial, and seeing that is the clearest evidence of progress the course can give you.


Ready to move on when

  • [ ] You scored 7 or more, or you scored lower and have re-answered the missed questions correctly
  • [ ] Lab 2 builds with no warnings and passes its checklist
  • [ ] You can explain, without notes, why a class-type parameter is a copy in C++
  • [ ] You can name the two situations this is needed in
  • [ ] You have written at least one const member function because the compiler forced you to, not because the notes said to

Next: Summary — what must be retained, and the checklist. · All modules