Essential C++--Exercise of Chpt.4
前言
本文用于记录阅读书籍《Essential C++》Chpt.4后完成课后习题。
正文(Code)
4.1 First Meeting with Header File
建立stack.h
和stack.suffix
,此处的suffix
是你的编译器所能接受的扩展名,或是你的项目所使用的扩展名。编写main()
函数,练习操作Stack
的所有公开接口,并加以编译执行。程序代码文件和main()
都必须包含stack.h
。
#include <iostream>
#include <string>
#include "stack.h"
using namespace std;
bool get_another_try()
{
char c_in;
bool bTry;
cout << "try it? (Y/y:yes N/n:no): ";
cin >> c_in;
bTry = ('Y' == c_in || 'y' == c_in);
if (!bTry && 'N' != c_in && 'n' != c_in)
{
cout << "invalid input: " << c_in << endl;
}
return bTry;
}
int main()
{
Stack stk;
int r;
r = init_stack(stk);
if (0 != r)
{
cout << "init stack failed!" << endl;
return -1;
}
string str_tmp;
while(get_another_try())
{
cout << "pls input test choice(0:test pop, 1:test peek, 2:test empty, 3:test full): ";
cin >> r;
switch(r)
{
// test pop
case 0:
{
if (!(stk.pop(str_tmp)))
{
cout << "test pop failed!" << endl;
break;
}
cout << "get pop string: " << str_tmp
<< ", cur size: " << stk.size() << endl;
break;
}
// test peek
case 1:
{
if (!(stk.peek(str_tmp)))
{
cout << "test peek failed!" << endl;
break;
}
cout << "get peek string: " << str_tmp
<< ", cur size: " << stk.size() << endl;
break;
}
// test empty
case 2:
{
bool bEmpty = stk.empty();
cout << "get empty: " << bEmpty
<< ", cur size: " << stk.size() << endl;
break;
}
// test full
case 3:
{
bool bFull = stk.full();
cout << "get full: " << bFull
<< ", cur size: " << stk.size() << endl;
break;
}
default:
{
cout << "invalid input: " << r
<< ", cur size: " << stk.size() << endl;
break;
}
}
}
cout << "user exit!" << endl;
return 0;
}
stack.cpp
源文件如下所述:
#include "stack.h"
using namespace std;
bool
Stack::find(const string &str)
{
vector<string>::iterator it = _stack.begin();
while(it != _stack.end())
{
if (*it == str)
{
break;
}
it++;
}
return it != _stack.end();
}
int
Stack::count(const string &str)
{
int cnt = 0;
vector<string>::iterator it = _stack.begin();
while(it != _stack.end())
{
if (*it == str)
{
cnt++;
}
it++;
}
return cnt;
}
int init_stack(Stack &stk)
{
string str_arr[6] = {"a", "ab", "abc", "abcd", "abcde", "abcdef"};
for(int i = 0; i < 6; i++)
{
stk.push(str_arr[i]);
}
return 0;
}
stack.h
头文件如下所述:
#ifndef _STACK_H_
#define _STACK_H_
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Stack
{
public:
bool empty();
bool full();
bool peek(string &);
bool pop(string &);
bool push(const string &);
bool find(const string &);
int count(const string &);
int size();
private:
vector<string> _stack;
};
inline bool
Stack::empty(void)
{
return _stack.empty();
}
inline bool
Stack::full(void)
{
return (_stack.size() == _stack.max_size());
}
inline bool
Stack::peek(string &str)
{
if (_stack.empty())
{
return false;
}
str = _stack.back();
return true;
}
inline bool
Stack::pop(string &str)
{
if (_stack.empty())
{
return false;
}
str = _stack.back();
_stack.pop_back();
return true;
}
inline bool
Stack::push(const string &str)
{
_stack.push_back(str);
return true;
}
inline int
Stack::size()
{
return _stack.size();
}
int init_stack(Stack &stk);
#endif
4.2 Expand Class Stack
扩展Stack
的功能,以支持find()
和count()
两个操作。find()
会查看某值是否存在而返回true
或false
。count()
返回某字符串的出现次数。重新实现练习4.1的main()
,让它调用这两个函数。
#include <iostream>
#include <string>
#include "stack.h"
using namespace std;
bool get_another_try()
{
char c_in;
bool bTry;
cout << "try it? (Y/y:yes N/n:no): ";
cin >> c_in;
bTry = ('Y' == c_in || 'y' == c_in);
if (!bTry && 'N' != c_in && 'n' != c_in)
{
cout << "invalid input: " << c_in << endl;
}
return bTry;
}
int main()
{
Stack stk;
int r;
r = init_stack(stk);
if (0 != r)
{
cout << "init stack failed!" << endl;
return -1;
}
string str_tmp;
while(get_another_try())
{
cout << "pls input test choice(0:test pop, 1:test peek, 2:test empty, 3:test full, 4:test find, 5:test count): ";
cin >> r;
switch(r)
{
// test pop
case 0:
{
if (!(stk.pop(str_tmp)))
{
cout << "test pop failed!" << endl;
break;
}
cout << "get pop string: " << str_tmp
<< ", cur size: " << stk.size() << endl;
break;
}
// test peek
case 1:
{
if (!(stk.peek(str_tmp)))
{
cout << "test peek failed!" << endl;
break;
}
cout << "get peek string: " << str_tmp
<< ", cur size: " << stk.size() << endl;
break;
}
// test empty
case 2:
{
bool bEmpty = stk.empty();
cout << "get empty: " << bEmpty
<< ", cur size: " << stk.size() << endl;
break;
}
// test full
case 3:
{
bool bFull = stk.full();
cout << "get full: " << bFull
<< ", cur size: " << stk.size() << endl;
break;
}
// test find
case 4:
{
cout << "pls input string you wanna find: ";
cin >> str_tmp;
if (stk.find(str_tmp))
{
cout << "find string: " << str_tmp << ", from class stack" << endl;
}
else
{
cout << "not find string: " << str_tmp << endl;
}
break;
}
// test count
case 5:
{
cout << "pls input string you wanna find: ";
cin >> str_tmp;
r = stk.count(str_tmp);
cout << "find string: " << str_tmp << ", count: " << r << endl;
break;
}
default:
{
cout << "invalid input: " << r
<< ", cur size: " << stk.size() << endl;
break;
}
}
}
cout << "user exit!" << endl;
return 0;
}
注:拓展后的stack.cpp
和stack.h
参考4.1小节。
4.3 Create A new Class Including Several Data
考虑一下所定义的全局(global)
数据:
string program_name;
string version_stamp;
int version_number;
int tests_run;
int tests_passed;
类代码如下所示:
#include <iostream>
#include <string>
using namespace std;
class UserProfile
{
public:
string program_name;
string version_stamp;
int version_number;
int tests_run;
int tests_passed;
};
4.4 Create A new Class UserProfile
一份“用户概况记录(user profile)
”内含以下数据:登录记录、实际姓名、登入次数、猜过次数、猜对次数、等级—包括初级、中级、高级、专家,以及猜对百分比(可实时计算获得,或将其值存起来备用)。请写出一个名为UserProfile
的class
,提供以下操作:输入、输出、相等测试、不等测试。其constructor
必须能够处理默认的用户等级、默认的登录名称("guest")
。对于同样名为guest
的多个用户,你如何保证每个guest
有他自己独有的登录会话(login session)
,不会和其他人混淆?
#include <iostream>
#include <string>
#include "user_profile.h"
int main()
{
#if 1 // create an object, using default constructor
cout << "===== demo_1: create a class object, by default constructor! ====" << endl;
UserProfile user_profile;
string level2str[] = {"low", "middle", "high", "expert"};
cout << "user_name: " << user_profile.get_usr_name() << endl;
cout << "user_level: " << level2str[user_profile.get_usr_level()] << endl;
cout << "create object user_profile by default constructor end!" << endl;
cout << endl;
#endif
#if 1 // input an object by istream
cout << "===== demo_2: create a class object by istream! ====" << endl;
UserProfile user_profile_1;
cin >> user_profile_1; // std in
//user_profile_1.pr_obj(); // print object info
cout << "create user_profile_1 end!" << endl;
cout << endl;
#endif
#if 1 // output an object by ostream
cout << "===== demo_3: output a class object by ostream! ====" << endl;
cout << user_profile_1 << endl;
cout << "output user_profile_1 end!" << endl;
cout << endl;
#endif
#if 1 // equality function of class
cout << "===== demo_4: equality test! ====" << endl;
UserProfile user_profile_2;
cin >> user_profile_2; // std in
user_profile_2.pr_obj(); // print object info
cout << "get equality result: " << (user_profile_2 == user_profile_1) << endl;
cout << "equality test end!" << endl;
cout << endl;
#endif
#if 1 // inequality function of class
cout << "===== demo_5: inequality test! ====" << endl;
UserProfile user_profile_3;
cin >> user_profile_3; // std in
user_profile_3.pr_obj(); // print object info
cout << "get inequality result: " << (user_profile_3 == user_profile_2) << endl;
cout << "inequality test end!" << endl;
cout << endl;
#endif
cout << "demo end!" << endl;
return 0;
}
包含类UserProfile的头文件如下所述:
#ifndef _USER_PROFILE_H_
#define _USER_PROFILE_H_
#include <iostream>
#include <string>
#include <ctime>
using namespace std;
enum UserLevel_E
{
low_level,
middle_level,
high_level,
expert_level,
};
class UserProfile
{
public:
UserProfile(); // default constructor
friend ostream& operator<< (ostream &os, UserProfile &user_profile);
friend istream& operator>> (istream &is, const UserProfile &user_profile);
bool operator== (const UserProfile &user_profile);
bool operator!= (const UserProfile &user_profile);
// login_date
string get_usr_login_date() {return _login_date;}
int set_usr_login_date();
// user_name
string get_usr_name() {return _user_name;}
int set_usr_name(const string &usr_name);
// login_cnt
int get_login_cnt() {return _login_cnt;}
int set_login_cnt(const int &login_cnt);
// user_guess_cnt
int get_usr_guess_cnt() {return _user_guess_cnt;}
int set_usr_guess_cnt(const int &usr_guess_cnt);
// user_guess_correct_cnt
int get_usr_guess_correct_cnt() {return _user_guess_correct_cnt;}
int set_usr_guess_correct_cnt(const int &usr_guess_cor_cnt);
// user_level
UserLevel_E get_usr_level() {return _user_level;}
int set_usr_level(const UserLevel_E &usr_level);
// user_guess_percentage
float get_usr_guess_percentage() {return _user_guess_percentage;}
int set_usr_guess_percentage();
void pr_obj() const;
private:
string _login_date;
string _user_name;
int _login_cnt;
int _user_guess_cnt;
int _user_guess_correct_cnt;
UserLevel_E _user_level;
float _user_guess_percentage;
};
// constructor, default
inline UserProfile::UserProfile()
{
_user_level = middle_level;
_user_name = "guest";
}
inline bool
UserProfile::operator== (const UserProfile &user_profile)
{
return (("guest" != this->_user_name) && (this->_user_name == user_profile._user_name));
}
inline bool
UserProfile::operator!= (const UserProfile &user_profile)
{
return (this->_user_name != user_profile._user_name);
}
inline int
UserProfile::set_usr_login_date()
{
char str_buf[64]; // used for storing date-string
// todo: get current date
time_t tm;
time(&tm);
struct tm stTm;
localtime_r(&tm, &stTm);
// todo: convert into string
strftime(str_buf, 64, "%Y-%m-%d %H-%M-%S", &stTm);
this->_login_date = str_buf;
return 0;
}
inline int
UserProfile::set_usr_name(const string &usr_name)
{
this->_user_name = usr_name;
return 0;
}
inline int
UserProfile::set_login_cnt(const int &login_cnt)
{
this->_login_cnt = login_cnt;
return 0;
}
inline int
UserProfile::set_usr_guess_cnt(const int &usr_guess_cnt)
{
this->_user_guess_cnt = usr_guess_cnt;
return 0;
}
inline int
UserProfile::set_usr_guess_correct_cnt(const int &usr_guess_cor_cnt)
{
this->_user_guess_correct_cnt = usr_guess_cor_cnt;
return 0;
}
inline int
UserProfile::set_usr_level(const UserLevel_E &usr_level)
{
this->_user_level = usr_level;
return 0;
}
inline int
UserProfile::set_usr_guess_percentage()
{
this->_user_guess_percentage = (this->_user_guess_cnt == 0 ? 0.0f : ((float)this->_user_guess_correct_cnt / (float)this->_user_guess_cnt));
return 0;
}
inline void
UserProfile::pr_obj() const
{
cout << *(UserProfile *)this << endl;
}
ostream& operator<< (ostream &os, UserProfile &user_profile)
{
string level2str[] = {"low", "middle", "high", "expert"};
os << "user_name: " << user_profile.get_usr_name() << '\n';
os << "login_date: " << user_profile.get_usr_login_date() << '\n';
os << "login_cnt: " << user_profile.get_login_cnt() << '\n';
os << "user_guess_cnt: " << user_profile.get_usr_guess_cnt() << '\n';
os << "user_guess_correct_cnt: " << user_profile.get_usr_guess_correct_cnt() << '\n';
os << "user_level: " << level2str[user_profile.get_usr_level()] << '\n';
os << "user_guess_percentage: " << user_profile.get_usr_guess_percentage();
return os;
}
istream& operator>> (istream &is, UserProfile &user_profile)
{
// input format: user_name, login_date, login_cnt, user_guess_cnt, user_guess_correct_cnt, user_level
string usr_name;
int login_cnt, usr_level;
float usr_guess_cnt, usr_guess_cor_cnt;
cout << "user_name: ";
is >> usr_name;
cout << "login_cnt: ";
is >> login_cnt;
cout << "user_guess_cnt: ";
is >> usr_guess_cnt;
cout << "user_guess_correct_cnt: ";
is >> usr_guess_cor_cnt;
cout << "user_level(0:low, 1:middle, 2:high, 3:expert): ";
is >> usr_level;
// update input into class object
user_profile.set_usr_login_date();
user_profile.set_usr_name(usr_name);
user_profile.set_login_cnt(login_cnt);
user_profile.set_usr_guess_cnt(usr_guess_cnt);
user_profile.set_usr_guess_correct_cnt(usr_guess_cor_cnt);
user_profile.set_usr_level((UserLevel_E)usr_level);
user_profile.set_usr_guess_percentage();
return is;
}
#endif
4.5 Create A new Class Matrix
请实现一个4x4
的Matrix class
,至少提供以下接口:矩阵加法、矩阵乘法、打印函数print()
、复合运算符+=
,以及一组支持下标操作(subscripting)
的function call
运算符,像下面这样:
float& operator() (int row, int column);
float operator() (int row, int column) const;
主进程调试源代码如下所述:
#include <iostream>
#include <string>
#include "matrix.h"
using namespace std;
int main()
{
#if 1 // create matrix obj 0, by default constructor
cout << "=== create matrix obj 0, by default constructor ===" << endl;
Matrix matrix_0;
// dbg: print matrix info
matrix_0.pr_matrix();
cout << endl;
#endif
#if 1 // create matrix obj 1, using array which size if 16
cout << "=== create matrix obj 1, using array which size if 16 ===" << endl;
float arr[16] = {0,1,2,3, 4,5,6,7, 8,9,10,11, 12,13,14,15};
Matrix matrix_1(arr);
// dbg: print matrix info
matrix_1.pr_matrix();
cout << endl;
#endif
#if 1 // matrix add
cout << "=== test matrix add ===" << endl;
matrix_0.matrix_add(matrix_1);
// dbg: print matrix info
matrix_0.pr_matrix();
cout << "test matrix add end!" << endl;
cout << endl;
#endif
#if 1 // matrix multiple
cout << "=== test matrix multiple ===" << endl;
matrix_0.matrix_multi(matrix_1);
// dbg: print matrix info
matrix_0.pr_matrix();
cout << "test matrix multiple end!" << endl;
cout << endl;
#endif
#if 1
cout << "=== test operator += ===" << endl;
matrix_0 += matrix_1;
// dbg: print matrix info
matrix_0.pr_matrix();
cout << "test operator += end!" << endl;
cout << endl;
#endif
#if 1
cout << "=== test subscripting ===" << endl;
int row, col;
cout << "input row(0~3): ";
cin >> row;
cout << "input column(0~3): ";
cin >> col;
// dbg: print matrix info
float r = matrix_0(row, col);
cout << "test subscripting end! get r: " << r << endl;
cout << endl;
#endif
cout << "demo end!" << endl;
return 0;
}
包含类Matrix
定义的头文件Matrix.h
如下所述:
#ifndef _MATRIX_H_
#define _MATRIX_H_
#include <iostream>
#include <string>
using namespace std;
class Matrix
{
public:
Matrix();
Matrix(float arr[16]);
bool check_attr() const; // check if attribute of object is valid, true:valid, false:invalid
int matrix_add(Matrix &a);
int matrix_multi(Matrix &a);
void pr_matrix();
int operator+=(Matrix &a);
float& operator() (int row, int column);
float operator() (int row, int column) const;
private:
int _row; // row of matrix, fixed
int _col; // column of matrix, fixed
// todo: try using 2-d vector
float _matrix_arr[4][4]; // vector<vector<float>> _matrix;
};
inline
Matrix::Matrix()
{
// initialize matrix size
this->_row = 4;
this->_col = 4;
cout << "pls input default matrix(float): " << endl;
for(int i = 0; i < this->_row; i++)
{
for(int j = 0; j < this->_col; j++)
{
cout << "(" << i << ", " << j << "): ";
cin >> this->_matrix_arr[i][j];
}
}
}
inline
Matrix::Matrix(float arr[16])
{
// initialize matrix size
this->_row = 4;
this->_col = 4;
for(int i = 0; i < this->_row; i++)
{
for(int j = 0; j < this->_col; j++)
{
this->_matrix_arr[i][j] = arr[i*this->_col + j];
}
}
}
inline bool
Matrix::check_attr() const
{
return (this->_row == 4 && this->_col == 4);
}
inline int
Matrix::matrix_add(Matrix & a)
{
if (!this->check_attr())
{
return -1;
}
for(int i = 0; i < this->_row; i++)
{
for(int j = 0; j < this->_col; j++)
{
this->_matrix_arr[i][j] += a._matrix_arr[i][j];
}
}
return 0;
}
inline int
Matrix::matrix_multi(Matrix & a)
{
if (!this->check_attr())
{
return -1;
}
for(int i = 0; i < this->_row; i++)
{
for(int j = 0; j < this->_col; j++)
{
this->_matrix_arr[i][j] *= a._matrix_arr[i][j];
}
}
return 0;
}
inline void
Matrix::pr_matrix()
{
if (!this->check_attr())
{
return;
}
for(int i = 0; i < this->_row; i++)
{
for(int j = 0; j < this->_col; j++)
{
cout << this->_matrix_arr[i][j] << " ";
}
cout << endl;
}
}
inline int
Matrix::operator+= (Matrix &a)
{
this->matrix_add(a); // reuse function matrix_add
return 0;
}
inline float&
Matrix::operator() (int row, int column)
{
if (!this->check_attr())
{
cout << "invalid obj attr! row: " << this->_row << ", col: " << this->_col << endl;
return this->_matrix_arr[0][0];
}
if (row < 0 || row >= this->_row
|| column < 0 || column >= this->_col)
{
cout << "invalid args! row: " << row << ", col: " << column << endl;
return this->_matrix_arr[0][0];
}
return this->_matrix_arr[row][column];
}
inline float
Matrix::operator() (int row, int column) const
{
if (!Matrix::check_attr())
{
cout << "invalid obj attr! row: " << this->_row << ", col: " << this->_col << endl;
return this->_matrix_arr[0][0];
}
if (row < 0 || row >= this->_row
|| column < 0 || column >= this->_col)
{
cout << "invalid args! row: " << row << ", col: " << column << endl;
return this->_matrix_arr[0][0];
}
return this->_matrix_arr[row][column];
}
#endif
结语
个人阅读书籍《Essential C++》之余创建此专栏,用于记录完成每一章节后附录的exercise。如有问题,请各位不吝指正。