Essential C++学习笔记及源代码(第4章 基于对象编程风格)

第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) {} //构造函数初始化iterator;
    bool operator==(const Triangular_iterator &) const;   //比较iterator是否相等;
    bool operator!=(const Triangular_iterator &) const;   //比较iterator是否不相等;
    int operator*() const;                                //指针解引用运算符;
    Triangular_iterator &operator++();                    //前置自增运算符;
    Triangular_iterator operator++(int);                  //后置自增运算符;

private:
    void check_integrity() const; //判断_index索引是否合法;
    int _index;
};

class Triangular
{
public:
    Triangular(int len = 1, int bp = 1);
    Triangular(const Triangular &);
    Triangular &operator=(const Triangular &rhs);
    //3个构造函数;

    int length() const { return _length; }
    int beg_pos() const { return _beg_pos; }
    int elem(int pos) const;
    //获取vector长度, 起始位置, pos位置的元素值;

    void length(int nlen) { _length = nlen; }
    void beg_pos(int npos) { _beg_pos = npos; }
    //更改Triangular的长度大小和起始位置;

    bool next(int &val) const;
    void next_reset() const { _next = 1; }
    //获取元素值和重置_next指针;

    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);
    //只能访问静态成员, 此处访问的是成员vector<int> _elems;

    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; //作为Triangular类的iterator友元, 可访问private中的成员;
    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; //定义一个静态vector;

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); //添加元素直到vector长度大于等于length;
            ++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); //添加元素到vector中直到大于等于value;
        ++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; //判断2个Triangular类是否相等;
}

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(); //抛出一个异常类iterator_overflow;
    }
    if (_index > Triangular::_elems.size())
    {
        Triangular::gen_elements(_index); //添加元素到vector中直到长度大于等于_index;
    }
    return;
}

inline int Triangular_iterator::operator*() const
{
    check_integrity();
    return Triangular::_elems[_index]; //获取_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) //作为参数调用标准模板库函数find_if;
    {
        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 << "Read 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;
    //对于guest加入一个独一无二的会话标识符;
    _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;
    //输入: robin Intermediate 1 8 3
    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日 ----------------------------------------------------

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MZZDX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值