You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Person genius{ { 1879, 3, 14 }, "Einstein", "Albert" };
60
-
cout << genius.getName() << '\n';
58
+
Person genius{ { 1879y, March, 14d }, "Einstein", "Albert" };
59
+
cout << genius.getName() << " was born " << genius.getDob() << '\n';
61
60
}
62
61
```
63
62
@@ -69,19 +68,23 @@ Quite a few things to note about this program:
69
68
70
69
* The member variables are initialized using uniform initialization syntax; this forbids narrowing conversions, and there shouldn't be any as the parameter types should have been carefully chosen. (Older code may use parentheses here instead of braces.) The order of construction is the same as the way the member fields are laid out (after the `private:` access specifier); the order in the comma-separated initializers is unimportant (although you should try to replicate the order of the member fields, your compiler will warn if they differ). The constructor's body is empty here (although it must be present), and this is not unusual.
71
70
72
-
* The `Date` parameter is passed as `const`-reference instead of by value, as it is probably too big to fit in a single register to pass by value. The names are passed by value as `std::string_view` although in older code `const std::string&` would be common.
71
+
* The `std::chrono::year_month_day` parameter (itself initialized by uniform initialization) is passed as `const`-reference instead of by value, as it is probably too big to fit in a single register to pass by value. The names are passed by value as `std::string_view` although in older code `const std::string&` would be common.
73
72
74
73
* The member function `getName()` is declared `const` as it is guaranteed not to change any member variables. It returns a newly created `std::string` which must be returned by value.
75
74
76
-
* The member variable `date` is declared `const` as it will never need to be changed; of course it needs to be initialized by the constructor, but this is allowed. The member variables `familyname` and `firstname` need to be of type `std::string` (not `std::string_view` as for the constructor's parameters) for them to be guaranteed to exist for the lifetime of the class.
75
+
* The member variable `dob` is declared `const` as it will never need to be changed; of course it needs to be initialized by the constructor, and this case is allowed. The member variables `familyname` and `firstname` need to be of type `std::string` (not `std::string_view` as for the constructor's parameters) for them to be guaranteed to exist for the lifetime of the class.
76
+
77
+
* The member function `getDob()` is also declared `const` and returns a `const`-reference. It is possible to put this return value directly to a `std::ostream` as the Standard Library overloads `operator<<` for `std::chrono::year_month_day`.
77
78
78
79
**Experiment:**
79
80
80
81
* Add more `Person` variables to `main()`, and output their names.
81
82
82
83
* Rewrite the constructor to initialize the member variables in the body, instead of using the comma-separated list of member initializers.
83
84
84
-
* Write getters (all declared `const`) called `getFamilyName()`, `getFirstName()`, `getDOB()` avoiding creation of unnecessary temporary variables. Modify `main()` to use these.
85
+
* Modify this program to use `std::println()` instead of `cout`.
86
+
87
+
* Write getters (all declared `const`) called `getFamilyName()` and `getFirstName()` avoiding creation of unnecessary temporary variables. Modify `main()` to use these.
85
88
86
89
* Write setters called `setFamilyName()` and `setFirstName()`. Test these from `main()` again.
87
90
@@ -100,17 +103,18 @@ The following program defines three `class`es, the second and third of which der
100
103
```cpp
101
104
// 09-person2.cpp : model Person, Student and Employee as a class inheritance hierarchy
* The `Date` type has been moved to be inside the `Person`; its fully qualified name is therefore `Person::Date`; this has been done to illustrate how `struct`s and `class`es and be nested inside each other. (The type `std::year_month_day`, new to C++20, was not available in my compiler when this program was written.) A forward-declaration `struct Date;` is necessary to avoid having to define `Date` in full before the first constructor.
191
+
* A second constructor for `Person` taking only a `std::chrono::year_month_day` has been added. Setters can be used later to initialize or modify the other three member variables, which are left defaulted by this constructor (empty for the two `std::string`s and `false` for the `bool`).
192
192
193
-
* A second constructor for `Person` taking only a `Date` has been added. Setters can be used later to initialize or modify the other three member variables, which are left defaulted by this constructor (empty for the two `std::string`s and `false` for the `bool`).
194
-
195
-
* A `virtual` destructor has been addded to `Person`; if you remember one thing about inheritance, it should be that base classes need a virtual destructor. This is so that any heap objects of type `Student` or `Employee` assigned to a pointer of type `Person*` (including use of smart pointers), the correct destructor of the **derived** class can be found and thus called, avoiding memory leaks.
193
+
* A `virtual` destructor has been added to `Person`; if you remember one thing about inheritance, it should be that base classes need a virtual destructor. This is so that any heap objects of type `Student` or `Employee` assigned to a pointer of type `Person*` (including use of smart pointers), the correct destructor of the **derived** class can be found and thus called, avoiding memory leaks.
196
194
197
195
* The `getName()` function returns the name(s) provided by either the constructor or the setter(s) as a single `std::string`, ordered according to the member variable `familynamefirst`. (I hope this attempt at cultural inclusion doesn't offend anyone!)
198
196
199
-
* The `Date` type has been modified to try to fit it into 32-bits, so it is almost certainly passed more efficiently by value in a single register rather than by `const`-reference.
200
-
201
197
* The member variable `dob` is declared `protected:`, the other three are `private:`, as before.
202
198
203
199
* The `Student` type is derived from `Person` using the keyword `public`. If this keyword were omitted, none of `Person`'s `public:` members would be visible to users of `Student`, as `class`es default to private inheritance. The syntax is exactly as for `Pixel` inheriting from `Point` in Chapter 6.
@@ -208,13 +204,13 @@ Many things to note about this program:
208
204
209
205
* The base class portion of `Student` is initialized as `Person{ person }` where `person` is of type `const Person&`. Then the other two fields of `Student` are initialized. The constructor parameter variable `attended_classes` is passed as a `const vector<string>&` so that only one copy is made, which is when the member variable of the same name is initialized.
210
206
211
-
* A `public:` member function `getDOB()` makes the `protected:` member of the base class `dob` available to **users** of the derived class. It is declared `const` and returns a `const`-reference.
207
+
* A `public:` member function `getDob()` makes the `protected:` data member of the base class `dob` available to **users** of the derived class, in this case `Student`. It is declared `const` and returns a `const`-reference.
212
208
213
209
* The member function `getAttendedClasses()` returns a `const`-reference to `attended_classes`, therefore this `std::vector<string>` is made visible to the function which calls this member function, but is not modifiable.
214
210
215
211
* The `Employee` constructor takes three parameters, the third of which is optional. The base class portion is initialized in the same way as for `Student`.
216
212
217
-
* The member function `isBirthday()` takes a `Person::Date` as a parameter and compares the `day` and `month` fields with those of `dob`, returning `true` if they are the same, or `false` otherwise. (We're pretending "today" is March 14, 2020.)
213
+
* The member function `isBirthdayToday()` takes a `std::chrono::year_month_day` as a parameter and compares the return values of the `day()` and `month()` members with those of `dob`, returning `true` if they are the same, or `false` otherwise. (We're pretending "today" is March 14, 2024, so this function always returns `true`.)
218
214
219
215
* The member variable `employee_id` is not meant to be able to be changed, so is declared `const`. The setter `setSalary()` is defined so that `salary` can be updated, while the getter `getDetails()` returns an aggregate of both derived classmember variables by value.
220
216
@@ -232,7 +228,7 @@ Many things to note about this program:
232
228
233
229
* Write a second constructor for `Employee` to accomplish the same thing.
234
230
235
-
* Add `getDOB()` to `Employee`, as for `Student`. Now try to add it to `Person`, what do you find? Would a single `public:` getter in the base class be more useful than a `protected:` member variable?
231
+
* Add `getDob()` to `Employee`, as for `Student`. Now try to add it to `Person`, what do you find? Would a single `public:` getter in the base class be more useful than a `protected:` member variable?
236
232
237
233
* Add member functions `addAttendedClass()` and `removeAttendedClass()` to `Student`. Make them smart enough to handle duplicates/invalid parameters.
238
234
@@ -327,47 +323,39 @@ A couple of things to note:
327
323
Friends have access to all members of the `class` that declares them a `friend`, including those declared `private:` or `protected:`. Sometimes this is desirable, as shown in the following program:
328
324
329
325
```cpp
330
-
// 09-person3.cpp : define operator== and operator<< for Person class
326
+
// 09-person3.cpp : define operator<=> for Person class
* Global `operator==` is defined for `Date`. Note that if we used either `std::year_month_day` or `operator<=>` (both new in C++20, but not covered in this Tutorial), this definition would not be necessary. As this `Date` is a `struct` with all members `public:`, use of the keyword `friend` is not needed.
384
+
*Member`operator<=>` (the "spaceship operator") is defaulted for this roll-your-own `Date`; this is all that is needed for the equality and ordering comparisons to be defined for this class, with ordering performed member-wise starting with the first data member.
385
385
386
-
* Within the definition of `Person`, both global `operator==` and global `operator<<` are declared `friend`. This is more boilerplate that you can use in your own classes, changing all occurrences of `Person` to the name of your class. (They are identical to normal function declarations, other than the use of the `friend` keyword.)
386
+
* Within the definition of `Person`, global `operator<<`is declared as a `friend` function. This is more boilerplate that you can use in your own classes, changing parameter `const Person&` to the name of your class. (They are identical to normal function declarations, other than the use of the `friend` keyword.)
387
387
388
-
* Global `operator==` is defined for `Person`. Here the `std:::string` members are compared explicitly, before the `Date` members are compared, calling the previously defined `operator==` for `Date` automatically.
388
+
*Member`operator<=>` is defaulted for `Person`; with this code the `std:::string` members will be compared (`familyname` before `firstname`), before the `Date` members are compared.
389
389
390
390
* Global `operator<<` is also defined for `Person`, allowing objects to be put to `cout` (and any other `std::ostream`s) using `<<`. This needs to be a `friend` because it accesses `dob`.
391
391
@@ -395,11 +395,9 @@ Some things to note about this program:
395
395
396
396
* Now give them different names. What output do you get?
397
397
398
-
* Define global `operator<<` for `Date`. Can you remove the need for `operator<<` for `Person`, to itself be a `friend` of `class Person`?
399
-
400
-
* Make global `operator==` for `Person` compare `getName()`s. Can you remove the need for it to be a `friend`?
398
+
* Define global `operator<<` for `Date`. Can you remove the need for `operator<<` for `Person` to itself be a `friend` of `class Person`?
401
399
402
-
* Make `operator==` for `Person` a member function instead of a global function.
400
+
*Compare a few`Person`instances with similar or same family names and first names, storing them in a `std::set<Person>`. Write code to output them telephone-book style. Are they ordered in the way you would expect?
403
401
404
402
Classes can be declared `friend`s as well as functions, although this use is probably less common. The following program defines two `class`es `A` and `B` which are mutual friends, thus allowing member functions of either to access each other's `private:` members.
405
403
@@ -628,4 +626,4 @@ A lot of things to note about this program:
628
626
629
627
[^1]: Grady Booch, Robert A. Maksimchuk, Michael W. Engle, Bobbi J. Young, Jim Conallen, Kelli A. Houston *Object-Oriented Analysis and Design with Applications* (3rd ed. Pearson, 2007, ISBN-13: 9780201895513)
0 commit comments