17. Week 9 Tuesday: Review!
≪ 16. Week 8 Thursday: Tic-Tac-Toe, continued | Table of ContentsSince this week is Thanksgiving week, we probably won’t have time to code up a nontrivial project. Instead, we’ll focus on doing a couple of review problems targetting structs and classes, including the paradigm of RAII, const correctness, and public vs. private member variables. We haven’t had much chance to dive deep into these topics in discussion, but I hope that a few exam-style questions will be a good refresher.
In each of the following problems, your job is to determine if there are any build errors, runtime errors, or undefined behaviour in the provided program. If there is, explain what they are and which lines of code are responsible. Otherwise, determine the output of the program.
Problem 1.
1#include <iostream>
2
3using namespace std;
4
5struct Cat {
6 Cat() {
7 cout << "A cat just spawned." << endl;
8 }
9};
10
11class Dog {
12 Dog() {
13 cout << "A dog has been birthed." << endl;
14 }
15};
16
17struct Pets {
18 Cat cat;
19 Dog dog;
20
21 Pets(Cat _cat, Dog _dog) {
22 cat = _cat;
23 dog = _dog;
24 }
25};
26
27int main() {
28 Cat c1, c2;
29 Dog d;
30 Pets(c1, d);
31
32 return 0;
33}
Solution
There is a build error in the above code. By default, member functions and variables in a class are private rather than public; in particular, the default constructor for the Dog class is private and cannot be accessed from the main function. Thus line 29 is a build error.
Additionally, since the dog member variable in the Pets struct is not initialised using an initialiser list, it will be constructed using the default constructor, which again is private and inaccessible from the Pets class! So there is a build error somewhere on lines 21 through 24 (the precise location is line 21, but this is a minute detail).
To summarise, there are two key takeaways: first, the private and public “defaults” in classes and structs, respectively; second, the RAII paradigm sneakily producing a second build error within the Pets struct.
As a follow-up question, suppose we replaced the word class with struct on line 11. What would the output be?
For the next three problems, please refer to the following header file:
painting.hpp
1#ifndef PAINTING_HPP
2#define PAINTING_HPP
3
4#include <string>
5using namespace std;
6
7class Painting {
8private:
9 string name;
10 string artist;
11
12public:
13 Painting(string _name = "Untitled",
14 string _artist = "Anonymous")
15 : name(_name), artist(_artist) {}
16
17 Painting()
18 : name("Untitled"), artist("Anonymous") {}
19};
20
21#endif
Problem 2.
Problem 3.
Problem 4.
Solutions
The first two programs compile with no errors, undefined behaviour, or output. The third program encounters a build error when the command Painting p; is issued: C++ cannot resolve which constructor to call. Both the default constructor with no arguments and the constructor with two string parameters with default arguments are perfect matches.
The important thing to note is that the existence of potentially ambiguous function calls will not result in a build error. Again, the first two programs build and run without any issues. It’s only when you make an ambiguous function call that things go awry.
For the next two problems, please refer to the following header file:
frog.hpp
Problem 5.
Problem 6.
Solutions
Both programs run and produce an output of 30.
For the first program, this comes down to what the const keyword on a member function does: it labels all of the member variables as const. weight becomes a const double — a box containing a double whose value is not allowed to change. But weight_ref is a “constant reference to a non-const double”. Thinking of weight_ref as a label for a double box, C++ says that the label we call weight_ref is not allowed to change. The box that it labels, i.e. the box also labelled by weight, is freely accessible still!
The second program is trickier, and it’s something I threw in for fun and enrichment: one may be inclined to believe that there is a build error because weight would be a const double from the moment jimmy is conceived. Then one cannot bind weight_ref — a reference to a non-const double — to the const double weight. But this is not the case! C++ only marks the contents of the const Frog jimmy as const after the constructor is run…
If you’re finding this too easy or boring, here’s a coding project to tackle:
Challenge 7.
Design a plan for an implementation of the Casino game video poker with a ruleset of your choosing. Specifically,
- write down pseudocode for how the program should run,
- determine what objects need to have a
classassociated with them, and - fill out the member variables, constructors, and member functions of said classes. Which member functions should be
constand what should be madeprivate?
If you have time, get to work and implement the game! (:
(I think if you have a very good grasp of object-oriented programming, you can put together at least most of a plan within one discussion.)