Primer C++ 学习笔记(第十四章)

本书为Primer C++ 中文第五版

练习题笔记

在这里插入图片描述

(14.1)
没有区别的情况:运算符作用于类型正确的实参,如data1 + data2; operator+(data1, data2);
有区别的情况:运算符作用于错误的实参,使用会产生error
(14.2)
class Sales_data;
istream& operator>>(istream &is, Sales_data& sd);
ostream& operator<<(ostream &os, const Sales_data& sd);

class Sales_data {
private:
    string isBn;
    double price;
public:
    Sales_data() = default;
    Sales_data(double p, string ib): isBn(ib), price(p) { }
    friend istream& operator>>(istream &is, Sales_data& sd);
    friend ostream& operator<<(ostream &os, const Sales_data& sd);
    Sales_data& operator+(const Sales_data& sd) {
        if(isBn == sd.isBn) {
            price += sd.price;
        }
        return *this;
    }
    Sales_data& operator+=(const Sales_data& sd) {
        if(isBn == sd.isBn)
            price += sd.price;
        return *this;
    }
};

istream& operator>>(istream &is, Sales_data& sd) {
    is >> sd.isBn >> sd.price;
    return is;
}
ostream& operator<<(ostream &os, const Sales_data& sd) {
    os << sd.isBn << " " << sd.price << endl;
    return os;
}

void test2() {
    Sales_data sd0(2.58, "zlbook");
    Sales_data sd1(3.96, "zlbook");
    Sales_data sd2(4.25, "zlbook");
    Sales_data sd3(1.47, "zl");
    Sales_data sd4;
    cout << sd0;
    cin >> sd4;
    cout << "ad2+sd0" << endl;
    sd2 + sd0;
    cout << sd0;
    cout << sd2;
    cout << "ad3+=sd0" << endl;
    sd3 += sd0;
    cout << sd0;
    cout << sd3;
}
(14.3)
(a) const char *
(b) string
(c) vector
(d) string
(14.4)
判定标准:
=, [], (), ->必须是成员
复合赋值符一般来说应该是成员,但并非必须
改变对象状态的运算符或者与给定类型密切相关的运算符,如递增、递减和解引用,通常应该是成员
具有对称性的运算符可能转换任意一端的运算对象,如算术、相等性、关系和位运算符等,通常应该是非成员
通常不应该重载逗号、取地址、逻辑与和逻辑或运算符

类的成员: %=, ++, ->, ()
非类的成员: %, <<, ==
不应该被重载: &&
(14.5)
class Date {
public:
    Date(int y, int m, int d, string ins)
        : year(y), month(m), day(d), instructions(ins) { }
private:
    int year, month, day;
    string instructions;
};
这个类记录了某天的日期和当天的记录
应该需要重载 复合赋值符、相等性、关系、>><<运算符

在这里插入图片描述

(14.6)
ostream& operator<<(ostream &os, const Sales_data& sd) {
    os << sd.isBn << " " << sd.price;
    return os;
}
(14.7)
ostream& operator<<(ostream &os, const String& s) {
    os << s.p << s.sz;
    return os;
}
(14.8)
ostream& operator<<(ostream &os, const Date& d) {
    os << d.year << "年" << d.month << "月" << d.day << "日" << " :" << d.instructions;
    return os;
}

在这里插入图片描述

(14.9)
当读取操作发生错误时,输入运算符应该负责从错误中恢复
istream& operator>>(istream &is, Sales_data& sd) {
    is >> sd.isBn >> sd.price;
    if(!is) item = Sales_data();//输入失败,对象赋予默认的状态
    return is;
}
(14.10)
(a) 正常
(b) 输入失败,对象将被默认初始化
(14.11)
没有处理输入失败的情况,输入对象参数正常时则正常,不正确时将发生错误
(14.12)
istream& operator>>(istream &is, Date& d) {
    is >> d.year >> d.month << d.day << d.instructions;
    if(!is) d = Date();//输入失败,对象赋予默认的状态
    return is;
}

在这里插入图片描述

(14.13)
非类成员函数
ostream& operator<<(ostream &os, const String& s);
istream& operator>>(istream &is, Sales_data& sd);
Sales_data operator+(const Sales_data& lhs, const Sales_data& rhs);
类成员函数
Sales_data& Sales_data::operator+=(const Sales_data& rhs);
(14.14)
+=返回的是一个引用,可以占用更少的内存
(14.15)
不需要,因为日期相加没有意义

在这里插入图片描述

(14.16)
就实现其中一个StrBlob,其他的都大同小异,都定义成非成员函数
bool operator==(const StrBlob& lsb, const StrBlob& rsb);
bool operator!=(const StrBlob& lsb, const StrBlob& rsb);
(14.17)
需要
bool operator==(const Date& ld, const Date& rd) {
    return ld.year == rd.year &&
           ld.month == rd.month &&
           ld.day == rd.day &&
           ld.instructions == rd.instructions;
}
bool operator!=(const Date& ld, const Date& rd) {
    return !(ld == rd);
}

在这里插入图片描述

(14.18)
就实现其中一个StrBlob,其他的都大同小异,都定义成非成员函数
bool operator<(const StrBlob& lsb, const StrBlob& rsb);
bool operator>(const StrBlob& lsb, const StrBlob& rsb);
(14.19)
应该含有
bool operator<(const Date& ld, const Date& rd) {
    if(ld.year < rd.year) return true;
    else if(ld. year > rd.year) return false;
    else {
        if(ld.month < rd.month) return true;
        else if(ld.month > rd.month) return false;
        else {
            if(ld.day < rd.day) return true;
            else if(ld.day > rd.day) return false;
            else {
                if(ld.instructions < rd.instructions) return true;
                else return false;
            }
        }
    }
}
bool operator>(const Date& ld, const Date& rd) {
    return !(ld < rd) && (ld != rd);
}

在这里插入图片描述

(14.20)
非类成员函数
Sales_data operator+(const Sales_data& lhs, const Sales_data& rhs);
类成员函数
Sales_data& Sales_data::operator+=(const Sales_data& rhs);
(14.21)
//+调用+=
Sales_data operator+(const Sales_data& lhs, const Sales_data& rhs) {
    Sales_data sum = lhs;
    sum += rhs;
    return sum;
}
Sales_data& Sales_data::operator+=(const Sales_data& rhs) {
    units_sold += rhs.units_sold;
    revenue += rhs.revenue;
    return *this;
}
//+=调用+
Sales_data operator+(const Sales_data& lhs, const Sales_data& rhs) {
    Sales_data sum = lhs;
    sum.units_sold += rhs.units_sold;
    sum.revenue += rhs.revenue;
    return sum;
}
Sales_data& Sales_data::operator+=(const Sales_data& rhs) {
    return *this + rhs;
}
可读性降低
(14.22)
Sales_data& Sales_data::operator=(const string& s) {
    ISBN = s;
    return *this;
}
(14.23)
StrVec& StrVec::operator=(initializer_list<string> il) {
    auto data = alloc_n_copy(il.begin(), il.end());
    free();
    elements = data.first;
    first_free = cap = data.second;
    return *this;
}
(14.24)
不需要
(14.25)
不需要

在这里插入图片描述

(14.26)
如果一个类包含下标运算符,通常会定义两个版本:
一个返回普通引用,一个是类的常量成员并且返回常量引用
class StrVec {
public:
    string& operator[](size_t n) {return elements[n]; }
    const string& operator[](size_t n) const {
        return elements[n];
    }
private:
    string* elements;
};

在这里插入图片描述

(14.27)
class StrBlobPtr {
public:
    //前置版本
    StrBlobPtr& operator++() {
        check(curr, "increment past end of StrBlobPtr");
        ++curr;
        return *this;
    }
    StrBlobPtr& operator--() {
        --curr;
        check(curr, "decrement past begin of StrBlobPtr");
        return *this;
    }
    //后置版本
    StrBlobPtr operator++(int) {
        StrBlobPtr ret = *this;
        ++*this;
        return ret;
    }
    StrBlobPtr operator--(int) {
        StrBlobPtr ret = *this;
        --*this;
        return ret;
    }
};
(14.28)
StrBlobPtr operator+(int n) {
    StrBlobPtr ret = *this;
    ret.curr += n;
    check(ret.curr, "increment error");
    return ret;
}
StrBlobPtr operator-(int n) {
    StrBlobPtr ret = *this;
    ret.curr -= n;
    check(ret.curr, "decrement error");
    return ret;
}
(14.29)
因为递增和递减会改变当前对象值

在这里插入图片描述

(14.30)
class ConstStrBlobPtr{
public:
    const string& operator*() const {
        auto p = check(curr, "dereference past end");
        return (*p)[curr];
    }
    const string* operator->() const {
        return & this->operator*();
    }
};
(14.31)
因为StrBlobPtr类的成员有拷贝构造函数、赋值运算符及析构函数,不需要再次声明定义。
(14.32)
class Test {
public:
    string* operator->() const {
        return sbp->operator->();
    }
private:
    StrBlobPtr *sbp;
};

在这里插入图片描述

(14.33)
一个类可以定义多个不同版本的调用运算符,其参数数量可以为0或任意正整数
(14.34)
template <typename T>
class ite {
public:
    T operator()(T t1, T t2, T t3) const {
        return t1 ? t2 : t3;
    }
};

void test34() {
    ite <int>i;
    ite <double>d;
    cout << i(0, 2, 3) << endl;
    cout << d(1.2, 2.3, 3.4) << endl;
}
(14.35)
class PrintString {
public:
    PrintString(istream &i): is(i) { }
    string operator()()const{
        string line;
        if(!getline(is, line)) line = "";
        return line;
    }
private:
    istream& is;
};

void test35() {
    PrintString ps(cin);
    cout << ps() << endl;
}
(14.36)
void test36() {
    PrintString ps(cin);
    vector<string> vs;
    while(1) {
        string line = ps();
        if(!line.empty())
            vs.push_back(line);
        else break;
    }
    for(auto s : vs) cout << s << " ";
    cout << endl;
}
(14.37)
template <typename T>
class equality {
public:
    bool operator()(T a, T b) const {
        return a == b;
    }
};

void test37() {
    vector<int> vi = {0, 1, 2, 3, 4, 2, 3, 2, 3};
    equality<int> ei;
    for_each(vi.begin(), vi.end(), [ei](int& i){if(ei(2, i)) i = 100;});
    for(auto i : vi) cout << i << " ";
    cout << endl;
}

在这里插入图片描述

(14.38)
class SizeComp{
public:
    SizeComp(size_t n): sz(n) { }
    bool operator()(const string& s) const {
        return s.size() == sz;
    }
private:
    size_t sz;
};

void test38() {
    ifstream fin("text.txt");
    string line;
    vector<string> vs;
    while(getline(fin, line) && !fin.eof()) {
        istringstream ss(line);
        string word;
        while(ss >> word) {
            vs.push_back(word);
        }
    }
    for(int i = 1; i < 11; ++i) {
        cout << i << ": " << count_if(vs.begin(), vs.end(), SizeComp(i)) << endl;
    }
}
(14.39)
void test39() {
    ifstream fin("text.txt");
    string line;
    vector<string> vs;
    while(getline(fin, line) && !fin.eof()) {
        istringstream ss(line);
        string word;
        while(ss >> word) {
            vs.push_back(word);
        }
    }
    cout << "1-9: " << count_if(vs.begin(), vs.end(), [](const string& s){return s.size()>0&&s.size()<10;}) << endl;
    cout << ">=10: " << count_if(vs.begin(), vs.end(), [](const string& s) {return s.size() >= 10;}) << endl;
}
(14.40)
class BigOpe {
public:
    bool operator()(const string& s1, const string& s2) const {
        return s1.size() < s2.size();
    }
    bool operator()(const string& s) {
        return s.size() >= 5;
    }
};
class PrintStr {
public:
    void operator()(const string& s) {
        cout << s << " ";
    }
};

void biggies(vector<string> &words, vector<string>::size_type sz) {
    sort(words.begin(), words.end());
    auto end_unique = unique(words.begin(), words.end());
    words.erase(end_unique, words.end());
    stable_sort(words.begin(), words.end(),
                [](const string &s1, const string &s2){return s1.size() < s2.size();});
    auto wc = find_if(words.begin(), words.end(),
                [sz](string &s){return s.size() >= sz;});
    auto count = words.end() - wc;
    cout << count << " "<< (count > 1 ? "words" : "word") << " of length "
         << sz << " or longger" << endl;
    for_each(wc, words.end(), [](string &s){ cout << s << " ";});
    cout << endl;

}

void test40() {
    vector<string> sve = {"the", "quick", "red", "fox", "jumps", "over", "the", "slow", "red", "turtle"};
    cout << "lambda" << endl;
    biggies(sve, 5);
    cout << "class" << endl;
    sort(sve.begin(), sve.end());
    auto end_unique = unique(sve.begin(), sve.end());
    sve.erase(end_unique, sve.end());
    stable_sort(sve.begin(), sve.end(), BigOpe());
    auto wc = find_if(sve.begin(), sve.end(), BigOpe());
    auto count = sve.end() - wc;
    cout << count << " "<< (count > 1 ? "words" : "word") << " of length 5"
         << " or longger" << endl;
    for_each(wc, sve.end(), PrintStr());
    cout << endl;
}
(14.41)
如果是简单的判断逻辑的话,更愿意使用lambda,感觉使用类有点大材小用了

在这里插入图片描述在这里插入图片描述

/**
*template<class Operation, class T>
*binder2nd<Operation> bind2nd (const Operation& op, const T& x) {
*   return binder2nd<Operation>(op, typename Operation::second_argument_type(x));
*}
*template<class Operation, class T>
*binder1st<Operation> bind1st (const Operation& op, const T& x) {
*   return binder1st<Operation>(op, typename Operation::first_argument_type(x));
*}
*bind2nd 表示 op(const T& t, x)
*bind1st 表示 op(x, const T& t)
*x为调用的时候里面的值,t为该函数捕捉到的值
*/
(14.42)
void test42() {
    vector<int> vi = {0, 1, 1038, 2022, 5, 1111, 100};
    vector<string> vs = {"pooh", "pooh", "test", "pooh"};
    auto sum = count_if(vi.begin(), vi.end(), bind2nd(greater<int>(), 1024));
    cout << sum << endl;
    auto first = find_if(vs.begin(), vs.end(), bind2nd(not_equal_to<string>(), "pooh"));
    cout << *first << endl;
    transform(vi.begin(), vi.end(), vi.begin(), bind2nd(multiplies<int>(), 2));
    for(auto i : vi) cout << i << " ";
    cout << endl;
}
(14.43)
void test43() {
    modulus<int> mo;
    cout << 3%9<< " " << 9%3 << endl;
    cout << mo(3, 9)<< " " << mo(9, 3) << endl;
    vector<int> vi = {3, 6, 9, 12 ,15 ,18 ,21};
    for(auto i : vi) cout << i << " ";
    cout << endl << "please input a number :\n";
    int num;
    while(cin >> num && num != 0) {
        int res = count_if(vi.begin(), vi.end(), bind2nd(modulus<int>(), num));
        //cout << res << endl;
        if(res == 0) {
            cout << "could" << endl;
        }else {
            cout << "couldn't" << endl;
        }
    }
}

在这里插入图片描述

(14.44)
int add(int i, int j) {return i+j;}
auto mod = [](int i, int j) {return i % j;};
struct divide {
    int operator()(int i, int j) {
        return i / j;
    }
};
void test44() {
    map<string, function<int(int, int)>> binops = {
        {"+", add},
        {"-", minus<int>()},
        {"/", divide()},
        {"%", mod},
        {"*", [](int i, int j) { return i * j;} }
    };
    cout << "10+2=: " << binops["+"](10,2) << endl;
    cout << "10-2=: " << binops["-"](10,2) << endl;
    cout << "10/2=: " << binops["/"](10,2) << endl;
    cout << "10%2=: " << binops["%"](10,2) << endl;
    cout << "10*2=: " << binops["*"](10,2) << endl;
}

在这里插入图片描述

(14.45)
string 应该返回 bookID
double 应该返回 revenue
(14.46)
不应该,因为Sales_data中的成员函数都不是唯一属性,三个成员函数结合在一起组成Sales_data;
如果定义了需要被声明成explicit,防止隐式转换产生错误。
(14.47)
operator const int(); 表示将对象定义成const int类型并返回
operator int() const; 表示改函数是const的,返回的是int类型
(14.48)
可以为Date提供一个bool类型的转换云算符,检查日期是否有效;
bool的类型转换通常用在条件部分,因此operator bool一般定义成explicit(14.49)
class Date {
public:
    Date(int y, int m, int d): year(y), month(m), day(d) { }
    explicit operator bool() const {
        if((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
            return month>0 && month<12 && day>0 && day <= month0[month] && year > 0;
        else
            return month>0 && month<12 && day>0 && day <= month1[month] && year > 0;
    }
private:
    int year, month, day;
    int month0[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
    int month1[12] = {31,29,31,30,31,30,31,31,30,31,30,31};
};

void test49() {
    Date b(1997,7,24);
    cout << static_cast<bool>(b) << endl;
    Date b1(1997,-7,24);
    cout << static_cast<bool>(b1) << endl;
}

在这里插入图片描述

(14.50)
ex1是int类型,所以ldObj需要转换成int,但是ldObj没有直接转换的,产生二义性
ex2是float类型,而ldObj有转换float类型的转换,调用operator float()转换
(14.51)
会优先调用标准类函数

在这里插入图片描述

(14.52)
ld = si + ld;
因为SmallInt和LongDouble不能互相转换,si会转换成int,LongDouble会转换成floatdouble,产生二义性;
ld = ld + si;
SmallInt和LongDouble不能互相转换,但是LongDouble中operator+接受为SmallInt类型的参数
所以会调用LongDouble的operator+
(14.53)
不合法,候选操作:
operator+(int, double)
SmallInt operator+(const SmallInt&, const SmallInt&)
应该改为:
double d = static_cast<double>(s1) + 3.14;
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值