第4章介绍了C++语言中使用Class进行基于对象的编程的方式
导言:一般而言,class由两部分组成:一组公开的(public)操作函数和运算符,以及一组私有的(private)实现细节。这些操作函数和运算符称为class的成员函数,并代表这个class的公开接口。身为class的用户只能访问其公开接口。这也就是我们使用string、vector等标准模板库的方式。例如,针对string的成员函数size(),我们只知道其原型声明,即参数列表为void,返回一个整数值。
1、Class的private实现细节可由成员函数的定义以及与class相关的任何数据组成。例如,假设string类对象的size()每次被调用,都会重新计算其字符串长度,那么就不需要任何相关的数据来存储这份信息,size()定义中可能利用for循环之类的遍历方式取得字符串长度。但如果string类对象想存储其字符串长度,就必须在每个class对象中定义一个private的数据成员,并在size()定义中将该值返回。每当字符串长度有所变动,这份private数据成员就必须被更新。
2、Class用户通常不会关心此等实现细节。身为一个用户,我们只利用其公开接口来进行编程。这种情形下,只要接口没有更改,即使实现细节重新构造,所有的应用程序代码也无须变动。
3、这一章我们学习将从class的使用提升至class的设计与实现。这正是C++程序员的主要工作。
本章作者使用了一个Triangular类来模拟一个class的实现,并教导读者在实现一个class的过程中需注意的细节。当私有成员有pointer成员时必须重载复制构造函数和赋值运算符防止内存越界。在本章最后引出一个例子简要体现第5章面向对象编程的含义。
附上笔者所写的课后练习答案。
//ch4_main.cpp
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
class Triangular_iterator
{
public:
Triangular_iterator(int index) : _index(index - 1) {}
bool operator==(const Triangular_iterator &) const;
bool operator!=(const Triangular_iterator &) const;
int operator*() const;
Triangular_iterator &operator++();
Triangular_iterator operator++(int);
private:
void check_integrity() const;
int _index;
};
class Triangular
{
public:
Triangular(int len = 1, int bp = 1);
Triangular(const Triangular &);
Triangular &operator=(const Triangular &rhs);
int length() const { return _length; }
int beg_pos() const { return _beg_pos; }
int elem(int pos) const;
void length(int nlen) { _length = nlen; }
void beg_pos(int npos) { _beg_pos = npos; }
bool next(int &val) const;
void next_reset() const { _next = 1; }
static bool is_elem(int);
static void gen_elements(int length);
static void gen_elems_to_value(int value);
static void display(int length, int beg_pos, ostream &os = cout);
typedef Triangular_iterator iterator;
Triangular_iterator begin() const
{
return Triangular_iterator(_beg_pos);
}
Triangular_iterator end() const
{
return Triangular_iterator(_beg_pos + _length);
}
private:
friend class Triangular_iterator;
int _length;
int _beg_pos;
mutable int _next;
enum
{
_max_elems = 1024
};
static vector<int> _elems;
};
ostream &operator<<(ostream &os, const Triangular &rhs)
{
os << "( " << rhs.beg_pos() << " , " << rhs.length() << " ) ";
rhs.display(rhs.length(), rhs.beg_pos(), os);
return os;
}
istream &operator>>(istream &is, Triangular &rhs)
{
char ch1, ch2;
int bp, len;
is >> ch1 >> bp >> ch2 >> len;
rhs.beg_pos(bp);
rhs.length(len);
rhs.next_reset();
return is;
}
Triangular::Triangular(int len, int beg_pos) : _length(len > 0 ? len : 1), _beg_pos(beg_pos > 0 ? beg_pos : 1)
{
_next = _beg_pos;
int elem_cnt = _beg_pos + _length;
if (_elems.size() < elem_cnt)
{
gen_elements(elem_cnt);
}
}
Triangular::Triangular(const Triangular &rhs) : _length(rhs._length), _beg_pos(rhs._beg_pos), _next(rhs._next)
{
}
int sum(const Triangular &trian)
{
if (0 == trian.length())
{
return 0;
}
int val, sum = 0;
trian.next_reset();
while (trian.next(val))
{
sum += val;
}
return sum;
}
int Triangular::elem(int pos) const
{
return _elems[pos - 1];
}
bool Triangular::next(int &value) const
{
if (0 == _next)
{
return false;
}
if (_next < _beg_pos + _length)
{
value = _elems[_next++];
return true;
}
_next = 0;
return false;
}
Triangular &Triangular::operator=(const Triangular &rhs)
{
if (this != &rhs)
{
_length = rhs._length;
_beg_pos = rhs._beg_pos;
_next = 1;
}
return *this;
};
vector<int> Triangular::_elems;
bool Triangular::is_elem(int value)
{
if (0 == _elems.size() || _elems[_elems.size() - 1] < value)
{
gen_elems_to_value(value);
}
return find(_elems.begin(), _elems.end(), value) != _elems.end();
}
void Triangular::gen_elements(int length)
{
if (length < 0 || length > _max_elems)
{
cerr << "Triangular Sequence: oops: invalid size: ";
cerr << length << " -- max size is ";
cerr << _max_elems << endl;
return;
}
if (_elems.size() < length)
{
int ix = _elems.size() ? _elems.size() + 1 : 1;
while (ix <= length)
{
_elems.push_back(ix * (ix + 1) / 2);
++ix;
}
}
return;
}
void Triangular::gen_elems_to_value(int value)
{
int ix = _elems.size();
if (0 == ix)
{
_elems.push_back(1);
ix = 1;
}
while (_elems[ix - 1] < value && ix < _max_elems)
{
_elems.push_back(ix * (ix + 1) / 2);
++ix;
}
if (ix == _max_elems)
{
cerr << "Triangular Sequence: oops: value too large ";
cerr << value << " -- exceeds max size of ";
cerr << _max_elems << endl;
}
return;
}
void Triangular::display(int length, int beg_pos, ostream &os)
{
if (length <= 0 || beg_pos <= 0)
{
cerr << "invalid parameters -- unable to fulfill request: ";
cerr << length << ", " << beg_pos << endl;
return;
}
int elems = beg_pos + length - 1;
if (_elems.size() < elems)
{
gen_elements(elems);
}
for (int ix = beg_pos - 1; ix < elems; ++ix)
{
os << _elems[ix] << ' ';
}
return;
}
inline bool Triangular_iterator::operator==(const Triangular_iterator &rhs) const
{
return _index == rhs._index;
}
inline bool Triangular_iterator::operator!=(const Triangular_iterator &rhs) const
{
return !(*this == rhs);
}
class iterator_overflow
{
};
inline void Triangular_iterator::check_integrity() const
{
if (_index > Triangular::_max_elems)
{
throw iterator_overflow();
}
if (_index > Triangular::_elems.size())
{
Triangular::gen_elements(_index);
}
return;
}
inline int Triangular_iterator::operator*() const
{
check_integrity();
return Triangular::_elems[_index];
}
inline Triangular_iterator &Triangular_iterator::operator++()
{
++_index;
check_integrity();
return *this;
}
inline Triangular_iterator Triangular_iterator::operator++(int)
{
Triangular_iterator tmp = *this;
++_index;
check_integrity();
return tmp;
}
class LessThan
{
public:
LessThan(int val) : _val(val) {}
int comp_val() const { return _val; }
void comp_val(int nval) { _val = nval; }
bool operator()(int value) const { return value < _val; }
private:
int _val;
};
int count_less_than(const vector<int> &vec, int comp)
{
int count = 0;
LessThan lt(comp);
for (int ix = 0; ix < vec.size(); ++ix)
{
if (lt(vec[ix]))
{
++count;
}
}
return count;
}
void print_less_than(const vector<int> &vec, int comp, ostream &os = cout)
{
LessThan lt(comp);
vector<int>::const_iterator iter = vec.begin();
vector<int>::const_iterator it_end = vec.end();
os << "elements less than " << lt.comp_val() << endl;
while ((iter = find_if(iter, it_end, lt)) != it_end)
{
os << *iter << ' ';
++iter;
}
os << endl;
return;
}
void prog1()
{
char ch;
int ival;
bool more = true;
while (more)
{
cout << "Enter value: ";
cin >> ival;
bool is_elem = Triangular::is_elem(ival);
cout << ival;
cout << (is_elem ? " is " : " is not ");
cout << "an element in the Triangular series.\n";
cout << "Another value? (y/n) ";
cin >> ch;
if (ch == 'n' || ch == 'N')
{
more = false;
}
}
return;
}
void prog2()
{
Triangular tri(20, 12);
Triangular::iterator it = tri.begin();
Triangular::iterator end_it = tri.end();
cout << "Triangular Series of " << tri.length() << " elements\n";
cout << tri << endl;
while (it != end_it)
{
cout << *it << ' ';
++it;
}
cout << endl;
}
void prog3()
{
int ia[16] = {17, 12, 44, 9, 18, 45, 6, 14,
23, 67, 9, 0, 27, 55, 8, 16};
vector<int> vec(ia, ia + 16);
int comp_val = 20;
cout << "Number of elements less than ";
cout << comp_val << " are ";
cout << count_less_than(vec, comp_val) << endl;
print_less_than(vec, comp_val);
return;
}
void prog4()
{
Triangular tri(6, 3);
cout << tri << endl;
Triangular tri2;
cout << "Please enter as the example (3, 5): ";
cin >> tri2;
cout << tri2 << endl;
return;
}
void prog5()
{
Triangular tri(4, 3);
Triangular::iterator it = tri.begin();
Triangular::iterator end_it = tri.end();
cout << "Triangular Series of " << tri.length() << " elements\n";
cout << tri << endl;
while (it != end_it)
{
cout << *it << ' ';
++it;
}
cout << endl;
return;
}
int main()
{
prog1();
prog2();
prog3();
prog4();
prog5();
return 0;
}
//-----------------------------------------------------------;
//-----------------------------------------------------------; //Practise 4.1 and 4.2.cpp
#include <iostream>
#include "Stack.h"
int main()
{
Stack st;
string str;
while (cin >> str && !st.full())
{
st.push(str);
}
cout << "\nRead in " << st.size() << " strings!\n";
cin.clear();
cout << "what word to search for? ";
cin >> str;
bool found = st.find(str);
int count = found ? st.count(str) : 0;
cout << str << (found ? " is " : " isn\'t ");
cout << "in the stack. ";
if (found)
{
cout << "It occurs " << count << " times\n";
}
return 0;
}
//-----------------------------------------------------------; //Stack.h
#ifndef STACK_H_
#define STACK_H_
#include <string>
#include <vector>
using namespace std;
class Stack
{
public:
bool push(const string &);
bool pop(string &elem);
bool peek(string &elem);
bool find(const string &elem) const;
int count(const string &elem) const;
bool empty() const { return _stack.empty(); }
bool full() const { return _stack.size() == _stack.max_size(); }
int size() const { return _stack.size(); }
private:
vector<string> _stack;
};
#endif
//-----------------------------------------------------------; //Stack.cpp
#include <algorithm>
#include "Stack.h"
bool Stack::pop(string &elem)
{
if (empty())
{
return false;
}
elem = _stack.back();
_stack.pop_back();
return true;
}
bool Stack::peek(string &elem)
{
if (empty())
{
return false;
}
elem = _stack.back();
return true;
}
bool Stack::push(const string &elem)
{
if (full())
{
return false;
}
_stack.push_back(elem);
return true;
}
bool Stack::find(const string &elem) const
{
return std::find(_stack.begin(), _stack.end(), elem) != _stack.end();
}
int Stack::count(const string &elem) const
{
return std::count(_stack.begin(), _stack.end(), elem);
}
//-----------------------------------------------------------;
//-----------------------------------------------------------; //Practise4.3.cpp
#include <iostream>
#include <string>
using namespace std;
class globalWrapper
{
public:
static int tests_passed() { return _tests_passed; }
static int tests_run() { return _tests_run; }
static int version_number() { return _version_number; }
static string version_stamp() { return _version_stamp; }
static string program_name() { return _program_name; }
static void tests_passed(int nval) { _tests_passed = nval; }
static void tests_run(int nval) { _tests_run = nval; }
static void version_number(int nval) { _version_number = nval; }
static void version_stamp(const string &nstamp) { _version_stamp = nstamp; }
static void program_name(const string &npn) { _program_name = npn; }
private:
static string _program_name;
static string _version_stamp;
static int _version_number;
static int _tests_run;
static int _tests_passed;
};
string globalWrapper::_program_name;
string globalWrapper::_version_stamp;
int globalWrapper::_version_number;
int globalWrapper::_tests_run;
int globalWrapper::_tests_passed;
int main()
{
if (globalWrapper::program_name().empty())
{
globalWrapper::program_name("ex_4_3");
globalWrapper::version_number(1);
globalWrapper::version_stamp("A1-OK");
}
if (globalWrapper::program_name() == "ex_4_3")
{
cout << "globalWrapper seems to work ok\n";
}
else
{
cout << "Hmm. globalWrapper doesn't seem to be correct\n";
}
return 0;
}
//-----------------------------------------------------------;
//-----------------------------------------------------------; //Practise4.4.cpp
#include <iostream>
#include <string>
using namespace std;
class UserProfile
{
public:
enum Level
{
Beginner,
Intermediate,
Advanced,
Professional
};
UserProfile();
UserProfile(string login, Level = Beginner) : _login(login), _user_level(level), _times_logged(1), _guesses(0), _correct_guesses(0) {}
bool operator==(const UserProfile &) { return _login == rhs._login && _user_name == rhs._user_name; }
bool operator!=(const UserProfile &rhs) { return !(*this == rhs); }
string login() const { return _login; }
string user_name() const { return _user_name; }
int login_count() const { return _times_logged; }
int guess_count() const { return _guesses; }
int guess_correct() const { return _correct_guesses; }
double guess_average() const { return _guesses != 0.0 ? double(_correct_guesses) / double(_guesses) * 100 : 0.0; }
string level() const;
void reset_login(const string &val) { _login = val; }
void user_name(const string &val) { _user_name = val; }
void reset_level(const string &);
void reset_level(Level newlevel) { _user_level = newlevel; }
void reset_login_count(int val) { _times_logged = val; }
void reset_guess_count(int val) { _guesses = val; }
void reset_guess_correct(int val) { _correct_guesses = val; }
void bump_login_count(int cnt = 1) { _times_logged += cnt; }
void bump_guess_count(int cnt = 1) { _guesses += cnt; }
void bump_guess_correct(int cnt = 1) { _correct_guesses += cnt; }
private:
string _login;
string _user_name;
int _times_logged;
int _guesses;
int _correct_guesses;
Level _user_level;
};
inline UserProfile::UserProfile() : _login("guest"), _user_level(Beginner), _times_logged(1), _guesses(0), _correct_guesses(0)
{
static int id = 0;
++id;
_login += to_string(id);
}
inline string UserProfile::level() const
{
static string _level_table[4] = {"Beginner", "Intermediate", "Advanced", "Professional"};
return _level_table[_user_level];
}
ostream &operator<<(ostream &os, const UserProfile &rhs)
{
os << rhs.login() << ' ';
os << rhs.level() << ' ';
os << rhs.login_count() << ' ';
os << rhs.guess_count() << ' ';
os << rhs.guess_correct() << ' ';
os << rhs.guess_average() << endl;
return os;
}
istream &operator>>(istream &is, UserProfile &rhs)
{
string login, level;
int lcount, gcount, gcorrect;
is >> login >> level;
is >> lcount >> gcount >> gcorrect;
rhs.reset_login(login);
rhs.reset_level(level);
rhs.reset_login_count(lcount);
rhs.reset_guess_count(gcount);
rhs.reset_guess_correct(gcorrect);
return is;
}
inline void UserProfile::reset_level(const string &level)
{
if (level == "Intermediate")
{
_user_level = Intermediate;
}
else if (level == "Advanced")
{
_user_level = Advanced;
}
else if (level == "Professional")
{
_user_level = Professional;
}
else
{
_user_level = Beginner;
}
return;
}
int main()
{
UserProfile anon;
cout << anon;
UserProfile anon_too;
cout << anon_too;
UserProfile anna("AnnaL", UserProfile::Professional);
cout << anna;
anna.bump_guess_count(27);
anna.bump_guess_correct(25);
anna.bump_login_count();
cout << anna;
cin >> anon;
cout << anon;
return 0;
}
//-----------------------------------------------------------;
//-----------------------------------------------------------; //Practise4.5.cpp
#include <iostream>
using namespace std;
typedef float elemType;
class Matrix
{
public:
Matrix(elemType = 0.0f, elemType = 0.0f, elemType = 0.0f, elemType = 0.0f,
elemType = 0.0f, elemType = 0.0f, elemType = 0.0f, elemType = 0.0f,
elemType = 0.0f, elemType = 0.0f, elemType = 0.0f, elemType = 0.0f,
elemType = 0.0f, elemType = 0.0f, elemType = 0.0f, elemType = 0.0f);
Matrix(const elemType *);
void operator+=(const Matrix &);
elemType &operator()(int row, int column)
{
return _matrix[row][column];
}
int rows() const { return 4; }
int cols() const { return 4; }
elemType operator()(int row, int column) const
{
return _matrix[row][column];
}
ostream &print(ostream &) const;
private:
friend Matrix operator+(const Matrix &, const Matrix &);
friend Matrix operator*(const Matrix &, const Matrix &);
elemType _matrix[4][4];
};
inline ostream &operator<<(ostream &os, const Matrix &m)
{
return m.print(os);
}
Matrix operator+(const Matrix &m1, const Matrix &m2)
{
Matrix result(m1);
result += m2;
return result;
}
Matrix operator*(const Matrix &m1, const Matrix &m2)
{
Matrix result;
for (int ix = 0; ix < m1.rows(); ix++)
{
for (int jx = 0; jx < m1.cols(); jx++)
{
result(ix, jx) = 0;
for (int kx = 0; kx < m1.cols(); kx++)
{
result(ix, jx) += m1(ix, kx) * m2(kx, jx);
}
}
}
return result;
}
void Matrix::operator+=(const Matrix &m)
{
for (int ix = 0; ix < 4; ++ix)
{
for (int jx = 0; jx < 4; ++jx)
{
_matrix[ix][jx] += m._matrix[ix][jx];
}
}
return;
}
ostream &Matrix::print(ostream &os) const
{
int cnt = 0;
for (int ix = 0; ix < 4; ++ix)
{
for (int jx = 0; jx < 4; ++jx, ++cnt)
{
if (cnt && !(cnt % 8))
{
os << endl;
}
os << _matrix[ix][jx] << ' ';
}
}
os << endl;
return os;
}
Matrix::Matrix(elemType a11, elemType a12, elemType a13, elemType a14,
elemType a21, elemType a22, elemType a23, elemType a24,
elemType a31, elemType a32, elemType a33, elemType a34,
elemType a41, elemType a42, elemType a43, elemType a44)
{
_matrix[0][0] = a11, _matrix[0][1] = a12;
_matrix[0][2] = a13, _matrix[0][3] = a14;
_matrix[1][0] = a21, _matrix[1][1] = a22;
_matrix[1][2] = a23, _matrix[1][3] = a24;
_matrix[2][0] = a31, _matrix[2][1] = a32;
_matrix[2][2] = a33, _matrix[2][3] = a34;
_matrix[3][0] = a41, _matrix[3][1] = a42;
_matrix[3][2] = a43, _matrix[3][3] = a44;
return;
}
Matrix::Matrix(const elemType *array)
{
for (int ix = 0; ix < 4; ++ix)
{
for (int jx = 0; jx < 4; ++jx)
{
_matrix[ix][jx] = *(array++);
}
}
return;
}
int main()
{
Matrix m;
cout << m << endl;
elemType ar[16] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
elemType ar2[16] = {1.3f, 0.4f, 2.6f, 8.2f, 6.2f, 1.7f, 1.3f, 8.3f,
4.2f, 7.4f, 2.7f, 1.9f, 6.3f, 8.1f, 5.6f, 6.6f};
Matrix identity(ar);
cout << identity << endl;
Matrix m2(identity);
m = identity;
cout << m2 << endl;
cout << m << endl;
Matrix m3(ar2);
cout << m3 << endl;
Matrix m4 = m3 * identity;
cout << m4 << endl;
Matrix m5 = m3 + m4;
cout << m5 << endl;
m3 += m4;
cout << m3 << endl;
return 0;
}
//-----------------------------------------------------------;
//--------------------------------------------2021年7月21日 ----------------------------------------------------
|