Skip to content

Commit 296f409

Browse files
authored
feat: add concept exercise for headers (#741)
1 parent 2f47f1a commit 296f409

18 files changed

+18451
-30
lines changed

.vscode/settings.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,5 +68,8 @@
6868
"cinttypes": "cpp",
6969
"typeinfo": "cpp",
7070
"variant": "cpp"
71-
}
71+
},
72+
"cSpell.words": [
73+
"stationprogress"
74+
]
7275
}

concepts/headers/about.md

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
# About
22

3-
In C++ declarations are often separated from definitions.
4-
Declarations are grouped into so-called header files and the respective implementation is placed in source files.
3+
In C++, declarations are often separated from definitions.
4+
Declarations are grouped into so-called header files, with the respective implementations placed in source files.
55
You can think of the header files as an API.
6-
The header file will tell you what a codebase has to offer without going into the details of how.
6+
The header file will tell you _what_ a codebase has to offer without going into the details of _how_.
77

88
## Header and Source
99

1010
The most common file extension for header files is `.h`.
1111
Some projects use `.hpp` or skip the extension completely.
1212

1313
The definitions are located in a separate `.cpp` file.
14-
To reunite both parts, this source file starts by including the respective header file.
14+
To reunite the parts, the source file starts by _including_ the respective header file.
1515

16-
If you want to write a library called "quick_math", that offers a function "super_root" that returns your favorite number, the files would look like this:
16+
If you want to write a library called "quick_math" that offers a function "super_root" that you want to use often, the files would look like this:
1717

1818
```cpp
1919
// A file named quick_math.h
@@ -33,19 +33,19 @@ double quick_math::super_root(double x, int n) {
3333
}
3434
```
3535

36-
If you need to include another header, that is only needed by the implementation, the respective `#include` line is only needed in the source file.
37-
Everything that is included in the header, is also available in the `.cpp` file, like the `string` library in the example below.
38-
Attention: the `;` is needed after the declaration in the header file, but not after the definition in the source file.
36+
If you need to include a header that is only required by the implementation, the respective `#include` line is only needed in the source file.
37+
Everything that is included in the header is also available in the `.cpp` file, like the `string` library in the example below.
38+
**Attention**: the `;` is needed after the declaration in the header file, but not after the definition in the source file.
3939

4040
~~~~exercism/note
4141
Many C++ exercises on Exercism start with two almost empty files: header and source.
42-
You have to check the `*_test.cpp` file to see the names and namespaces of the expected functions to solve the exercise.
42+
You have to check the `*_test.cpp` file to see the names and namespaces of the expected functions in order to solve the exercise.
4343
~~~~
4444

4545
## Classes and Headers
4646

4747
Classes can become very complex and their relation to the header / source partition might be confusing.
48-
One possible layout is to keep all the implementation details in the source file and the declarations and member variables in the header:
48+
One possible layout is to keep all the implementation details in the source file and all the declarations and member variables in the header:
4949

5050
```cpp
5151
// A file named robot_flower.h
@@ -82,7 +82,7 @@ When the header is used as an API overview, that is where a person would look fo
8282
The `size` parameter's default of the constructor is therefore handled in the header and not in the implementation.
8383
The definitions in the source file are prefixed with the namespace `robots` and the class type `Flower`.
8484
85-
Another option is a _header only_ library, that does not have a `.cpp` file at all:
85+
Another layout option is a _header only_ library, that does not have a `.cpp` file at all:
8686
8787
```cpp
8888
// A file named robot_flower.h
@@ -104,13 +104,13 @@ namespace robots {
104104
}
105105
```
106106

107-
Projects might use combinations of those layouts and there is a lot of discussion what might be the best fit for each use case.
107+
Projects might use combinations of these layouts and there is a lot of discussion as to what might be the best fit for each use case.
108108

109-
## Include Guards via pragma once
109+
## Include Guards
110110

111111
You may have noticed the `#pragma once` line in the example header file above.
112-
This include guard ensures that the content of the file is included only once during the compilation to avoid errors.
113-
There is another, more complex variation that starts with `#ifndef` which serves the same purpose, that is detailed below.
112+
This is called an include guard - and it ensures that the content of the file is included only once during the compilation to avoid errors.
113+
There is another, more complex variation of an include guard that starts with `#ifndef` and ends with `#endif`, that is detailed below.
114114

115115

116116
~~~~exercism/advanced

concepts/headers/introduction.md

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
# Introduction
22

3-
In C++ declarations are often separated from definitions.
4-
Declarations are grouped into so-called header files and the respective implementation is placed in source files.
3+
In C++, declarations are often separated from definitions.
4+
Declarations are grouped into so-called header files, with the respective implementations placed in source files.
55
You can think of the header files as an API.
6-
The header file will tell you what a codebase has to offer without going into the details of how.
6+
The header file will tell you _what_ a codebase has to offer without going into the details of _how_.
77

88
## Header and Source
99

1010
The most common file extension for header files is `.h`.
1111
Some projects use `.hpp` or skip the extension completely.
1212

1313
The definitions are located in a separate `.cpp` file.
14-
To reunite both parts, this source file starts by including the respective header file.
14+
To reunite the parts, the source file starts by _including_ the respective header file.
1515

16-
If you want to write a library called "quick_math", that offers a function "super_root" that you want to use often, the files would look like this:
16+
If you want to write a library called "quick_math" that offers a function "super_root" that you want to use often, the files would look like this:
1717

1818
```cpp
1919
// A file named quick_math.h
@@ -33,19 +33,19 @@ double quick_math::super_root(double x, int n) {
3333
}
3434
```
3535

36-
If you need to include another header, that is only needed by the implementation, the respective `#include` line is only needed in the source file.
37-
Everything that is included in the header, is also available in the `.cpp` file, like the `string` library in the example below.
38-
Attention: the `;` is needed after the declaration in the header file, but not after the definition in the source file.
36+
If you need to include a header that is only required by the implementation, the respective `#include` line is only needed in the source file.
37+
Everything that is included in the header is also available in the `.cpp` file, like the `string` library in the example below.
38+
**Attention**: the `;` is needed after the declaration in the header file, but not after the definition in the source file.
3939

4040
~~~~exercism/note
4141
Many C++ exercises on Exercism start with two almost empty files: header and source.
42-
You have to check the `*_test.cpp` file to see the names and namespaces of the expected functions to solve the exercise.
42+
You have to check the `*_test.cpp` file to see the names and namespaces of the expected functions in order to solve the exercise.
4343
~~~~
4444

4545
## Classes and Headers
4646

4747
Classes can become very complex and their relation to the header / source partition might be confusing.
48-
One possible layout is to keep all the implementation details in the source file and the declarations and member variables in the header:
48+
One possible layout is to keep all the implementation details in the source file and all the declarations and member variables in the header:
4949

5050
```cpp
5151
// A file named robot_flower.h
@@ -82,7 +82,7 @@ When the header is used as an API overview, that is where a person would look fo
8282
The `size` parameter's default of the constructor is therefore handled in the header and not in the implementation.
8383
The definitions in the source file are prefixed with the namespace `robots` and the class type `Flower`.
8484
85-
Another option is a _header only_ library, that does not have a `.cpp` file at all:
85+
Another layout option is a _header only_ library, that does not have a `.cpp` file at all:
8686
8787
```cpp
8888
// A file named robot_flower.h
@@ -104,11 +104,11 @@ namespace robots {
104104
}
105105
```
106106

107-
Projects might use combinations of those layouts and there is a lot of discussion what might be the best fit for each use case.
107+
Projects might use combinations of these layouts and there is a lot of discussion as to what might be the best fit for each use case.
108108

109109
## Include Guards
110110

111111
You may have noticed the `#pragma once` line in the example header file above.
112-
This include guard ensures that the content of the file is included only once during the compilation to avoid errors.
113-
There is another, more complex variation that starts with `#ifndef` and ends with `#endif`.
112+
This is called an include guard - and it ensures that the content of the file is included only once during the compilation to avoid errors.
113+
There is another, more complex variation of an include guard that starts with `#ifndef` and ends with `#endif`.
114114
It serves the same purpose and its usage is shown in the `Flower` class example above.

config.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,18 @@
168168
"classes",
169169
"comparisons"
170170
]
171+
},
172+
{
173+
"slug": "doctor-data",
174+
"name": "Doctor Data",
175+
"uuid": "2d2efdad-4f5d-4a1d-9626-381b37e72e3f",
176+
"concepts": [
177+
"headers"
178+
],
179+
"prerequisites": [
180+
"classes",
181+
"enums"
182+
]
171183
}
172184
],
173185
"practice": [
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Hints
2+
3+
## General
4+
5+
- Pay attention to any enumerators you come across.
6+
- The tests can only be run when you have implemented every task.
7+
To see the test results you only need a rough skeleton of the functions and classes.
8+
- Every function, class, and enumeration that is used by the tests must be declared in the header file.
9+
10+
## 1. Try to extract some first clues
11+
12+
- The class and the enum are in different namespaces.
13+
- Use a `class enum` for `System`
14+
- You can either have two constructors, or one constructor with a default argument.
15+
16+
## 2. Find more details
17+
18+
- The first `REQUIRE` line checks for the default `System`.
19+
- `generation` seems to increase by one in a cloned vessel.
20+
- The `System` seems to be untouched by the cloning process.
21+
22+
## 3. Look into the inner workings
23+
24+
- The `shoot_buster` member function seems to be depenedent on an internal counter.
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# Instructions
2+
3+
You start your first day at an Australian company called "Doctor Data", which specializes in information recovery.
4+
You aced your job interview through your knowledge of C++ and [von Neumann probes][van-neumann-probes].
5+
As you have seen a lot of test files, your new boss wants you to recreate the respective source and header files from some test code the company has recently recovered.
6+
7+
In this exercise, you are going to recreate lost files.
8+
9+
~~~~exercism/note
10+
The workflow of this concept exercise is very similar to the structure of Exercism's practice exercises.
11+
The exercise introduction text is only one part of the specification.
12+
The test file is your definitive guide to solving a given problem.
13+
Due to the way C++ compilation works, the test results might not show up in the web interface until you have implemented a minimal version of every class, function and enumeration that is required by the tests.
14+
If you receive compilation errors, they might disappear once you have addressed all tasks and tests.
15+
~~~~
16+
17+
You have four tasks, all related to recovering the lost code in the header and source files.
18+
19+
## 1. Try to extract some first clues
20+
21+
You look at two recovered lines from the test files:
22+
23+
```cpp
24+
heaven::Vessel bob{"Robert Johansson", 1};
25+
heaven::Vessel will{"Riker", 2, star_map::System::BetaHydri};
26+
```
27+
28+
Your sharp eye instantly recognized a namespace `heaven`.
29+
You also see that there must be a class called `Vessel`.
30+
The constructor can apparently be called with two or three arguments.
31+
The first argument seems to be of type `string`, the second one is a number.
32+
It is possible to initialize the `Vessel` class with a third argument.
33+
The third argument comes from a `star_map` namespace.
34+
It is an enumerator of type `System`.
35+
You even got one of the enumerations: `BetaHydri`.
36+
37+
Prepare the source and header files with your discovered information.
38+
You need two namespaces: `heaven` and `star_map`.
39+
The `heaven` namespace has a class `Vessel`, which can be called with two or three arguments.
40+
The `System` enum is to be placed in the `star_map` namespace and has an `EpsilonEridani` enumeration.
41+
Keep an eye out for other enumerations, so that you can constantly update the `System` enum.
42+
43+
## 2. Find more details
44+
45+
You uncover more lines from the test:
46+
47+
```cpp
48+
heaven::Vessel bob{"Robert Johansson", 1};
49+
REQUIRE(bob.current_system == star_map::System::Sol);
50+
REQUIRE(bob.generation == 1);
51+
heaven::Vessel bob5 = bob.replicate("Mario");
52+
REQUIRE(bob5.current_system == star_map::System::Sol);
53+
REQUIRE(bob5.generation == 2);
54+
```
55+
56+
The newly found test lines uncover another member function of the `Vessel` class: `replicate`.
57+
This function receives a string and returns another `Vessel` instance.
58+
You get an idea about the default value of the third argument of the constructor from the previous task.
59+
You also see two public member variables of the `Vessel` class and the specification of the `replicate` member function.
60+
61+
Add the `replicate` function and the public member variables `current_system` and `generation` to the header and source files.
62+
63+
## 3. Look into the inner workings
64+
65+
You find some more interesting lines in the recovered test files:
66+
67+
```cpp
68+
heaven::Vessel bob6{"Homer", 3, star_map::System::EpsilonEridani};
69+
REQUIRE(bob6.busters == 0);
70+
bob6.make_buster();
71+
REQUIRE(bob6.busters == 1);
72+
bool success = bob6.shoot_buster();
73+
REQUIRE(success);
74+
REQUIRE(bob6.busters == 0);
75+
success = bob6.shoot_buster();
76+
REQUIRE_FALSE(success);
77+
```
78+
79+
Apparently, the `Vessel` class has a member variable `busters`, that can be changed with the two class member functions `make_buster` and `shoot_buster`.
80+
Until other information surfaces, you take a guess that the `make_buster` function returns `void`.
81+
As there is a test for the return value of `shoot_buster`, you assume that the function returns a `bool`.
82+
83+
Add the two functions and the member variable to the `Vessel` class.
84+
Keep looking for other `System` enumerators.
85+
86+
## 4. Complete the picture
87+
88+
During your scan of the test files you find only two uncovered sections of the code:
89+
90+
```cpp
91+
heaven::Vessel bob1{"Bob", 1, star_map::System::AlphaCentauri};
92+
heaven::Vessel marv{"Marvin", 2, star_map::System::DeltaEridani};
93+
heaven::Vessel milo{"Milo", 3, star_map::System::DeltaEridani};
94+
heaven::Vessel howie{"Howard", 4, star_map::System::Omicron2Eridani};
95+
96+
REQUIRE("Bob" == heaven::get_older_bob(bob1, marv));
97+
REQUIRE(heaven::in_the_same_system(marv, milo));
98+
REQUIRE_FALSE(heaven::in_the_same_system(marv, howie));
99+
```
100+
101+
You see two functions, that are not members of the `Vessel` class, as they are not called with an instance.
102+
`get_older_bob` compares two `Vessel`instances and returns a `string`.
103+
`in_the_same_system` compares two `Vessel`instances and returns a `bool`.
104+
105+
Implement the last missing functions from the recovered lines above.
106+
107+
[van-neumann-probes]: https://en.wikipedia.org/wiki/Self-replicating_spacecraft

0 commit comments

Comments
 (0)