The keyword
throw
is used in
error()
, isn't it? So do I really need to use it explicitly? Or do you not remember what's going on in
error()
?
1 2 3 4 5 6 7 8 9 10
|
void error(const std::string& s)
{
using namespace std;
throw runtime_error(s);
}
void error(const std::string& s, const std::string& s2)
{
error(s + s2);
}
|
But yeah, it's
runtime_error
and not
invalid_argument
.
As for what should happen in case the input is fine, that's what the initializer after the colon is for, isn't it?
1 2
|
Person::Person(const std::string &name, const int age)
:m_name{ name }, m_age{ age }
|
The
:m_name{ name }, m_age{ age }
line should be telling the constructor what to do in case of valid input, right? Or do I still need to explicit within the constructor body?
Edit: Okay, I made the changes and now it works:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
// Osman Zakir
// 6 / 23 / 2017
// Bjarne Stroustrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 15 Class definition drill
// Drill Specifications:
/**
* 1. Define a struct Person containing a string name and an int age.
* 2. Define a variable of type Person , initialize it with “Goofy” and 63, and
* write it to the screen ( cout ).
* 3. Define an input ( >> ) and an output ( << ) operator for Person ; read in a
* Person from the keyboard ( cin ) and write it out to the screen ( cout ).
* 4. Give Person a constructor initializing name and age .
* 5. Make the representation of Person private, and provide const member
* functions name() and age() to read the name and age.
* 6. Modify >> and << to work with the redefined Person .
* 7. Modify the constructor to check that age is [0:150) and that name doesn’t
* contain any of the characters ; : " ' [ ] * & ^ % $ # @ ! . Use error() in case
* of error. Test.
* 8. Read a sequence of Person s from input ( cin ) into a vector<Person> ;
* write them out again to the screen ( cout ). Test with correct and errone-
* ous input.
* 9. Change the representation of Person to have first_name and second_name
* instead of name . Make it an error not to supply both a first and a second
* name. Be sure to fix >> and << also. Test.
*/
#include "../../cust_std_lib_facilities.h"
#include <iostream>
#include <vector>
#include <string>
struct Person
{
Person(const std::string &name, const int age);
Person();
std::string name() const { return m_name; }
int age() const { return m_age; }
void set_name(const std::string &name) { m_name = name; }
void set_age(const int age) { m_age = age; }
private:
std::string m_name;
int m_age;
};
std::ostream &operator<<(std::ostream &os, const Person &person);
std::istream &operator>>(std::istream &is, Person &person);
void fill_person_v(std::vector<Person> &persons_v);
void print_person_v(const std::vector<Person> &persons_v);
int main()
{
using namespace std;
try
{
vector<Person> persons_v;
fill_person_v(persons_v);
print_person_v(persons_v);
}
catch (const runtime_error &rte)
{
cerr << "Runtime error: " << rte.what() << '\n';
}
catch (const out_of_range &oor)
{
cerr << "Out of range error: " << oor.what() << '\n';
}
keep_window_open();
}
Person::Person(const std::string &name, const int age)
:m_name{ name }, m_age{ age }
{
if (age < 0 || age > 150)
{
error("age out of range");
}
else
{
m_age = age;
}
std::string bad_chars{ "\"\':;[]*&^%$#@!" };
auto found = m_name.find_first_of(bad_chars);
if (found != std::string::npos)
{
error("name is invalid");
}
else
{
m_name = name;
}
}
Person::Person()
: m_name{}, m_age{}
{
}
std::ostream &operator<<(std::ostream &os, const Person &person)
{
return os << person.name() << " -- age: " << person.age();
}
std::istream &operator>>(std::istream &is, Person &person)
{
using namespace std;
string name;
getline(is, name, '\n');
int age;
is >> age;
cin.ignore();
person = Person::Person{ name, age };
return is;
}
void fill_person_v(std::vector<Person> &persons_v)
{
using namespace std;
cout << "Enter some people's name and age (separate name and age by 'Enter' keypress, please)\n"
<< "end sequence of persons by entering '~'\n";
for (Person person; cin >> person;)
{
char ch;
cin.get(ch);
if (ch != '~')
{
cin.putback(ch);
persons_v.push_back(person);
}
else
{
cout << "Sequence ended\n";
break;
}
}
}
void print_person_v(const std::vector<Person> &persons_v)
{
using namespace std;
for (std::size_t i = 0; i < persons_v.size(); ++i)
{
cout << persons_v.at(i) << '\n';
}
}
|
As for the graphics stuff, it's still there in Chapter 15. Some of the exercises are also about graphics, and some of the drill also involves graphics (I did that part already). Chapter 15 is on graphing functions and it also talks about lambda expressions. Though I had to learn the hard way that capturing lambdas can't be used as the first argument to the Function constructor since you can't use it as a function pointer. The book uses a capturing lambda, but my compiler wouldn't let me do it so I had to find an alternative.
In Chapter 10, he explicitly says, "The graphical output and graphical user interactions are served by a vari-
ety of different libraries, and we will focus on that kind of I/O in Chapters 12 to 16.". So the graphics stuff apparently stays until Chapter 16.