C++ Primer第5版 第十四章课后练习答案

练习14.1

区别:

  1.可以直接调用重载的运算符

  2.至少有一个运算对象是类类型

  3.无法保留运算对象的求值顺序规则和短路求值规则

共同点:

  重载运算符的优先级和结合律与对应的内置运算符保持一致

练习14.2

#ifndef SALES_DATA_H
#define SALES_DATA_H
#include <string>
#include <ostream>
using std::string;
using std::istream;
using std::ostream;
using std::endl;
class Sales_data {
    friend istream& operator>>(istream& is, Sales_data& it);
    friend ostream& operator<<(ostream& os, Sales_data& it);
private:
    string bookNo;
    unsigned units_sold = { 0 };
    double revenue = { 0.0 };
public:
    const string& isbn() const { return bookNo; }
    Sales_data& operator+=(const Sales_data& rhs) {
        units_sold += rhs.units_sold;
        revenue += rhs.revenue;
        return *this;
    }
    Sales_data(string bn, unsigned us = 0, double re = 0.0) :bookNo(bn), units_sold(us), revenue(re) { std::cout << "Sales_data(string bn, unsigned us = 0, double re = 0.0)" << std::endl;}
    Sales_data() :Sales_data("") { std::cout << "Sales_data()" << std::endl; }
    Sales_data(istream& is) :Sales_data() { is>> *this; std::cout << "Sales_data(istream& is)" << std::endl; }
};

Sales_data operator+(Sales_data& lhs, Sales_data& rhs) {
    Sales_data sum = lhs;
    sum += rhs;
    return sum;
}

istream & operator>>(istream& is, Sales_data& it) {
    is >> it.bookNo >> it.units_sold >> it.revenue;
    return is;
}

ostream& operator<<(ostream& os, Sales_data& it) {
    os << it.isbn() << " " << it.units_sold << " " << it.revenue << endl;
    return os;
}

#endif // !SALES_DATA_H

练习14.3

 "cobble" == "stone";    //两者元素中既不是string也不是vector,因此两个版本都不是
 svec1[0] == svec2[0];    //string    
 svec1 == svec2;            //vector
 svec1[0] == "stone";    //string

练习14.4

(a) %    算数运算符,通常为普通的非成员函数

(b) %=   复合赋值运算符,通常为成员函数

(c) ++    改变对象状态的运算符,通常为成员函数

(d) ->    必须是成员函数

(e) <<    通常为普通的非成员函数

(f) &&    通常为普通的非成员函数

(g) ==    通常为普通的非成员函数

(h) ()    必须是成员函数

练习14.5

#ifndef DATE_H_
#define DATE_H_
#include<string>
using std::string;
class Date
{
public:
    Date(string&);
    ~Date();
    unsigned getYear()const { return year; }
    unsigned getMonth() const { return month; }
    unsigned getDay() const { return day; }
private:
    unsigned year;
    unsigned month;
    unsigned day;
    void str_to_month(string &str,string::size_type& pos);
};

Date::Date(string &s)
{
    string::size_type pos1, pos2;
    if (pos1 = s.find_first_of(",/") == string::npos) {
        pos1 = s.find_first_of(" ");
        pos2 = s.find_last_of(" ");
        str_to_month(s, pos1);
        day = stoul(s.substr(pos1 + 1, pos2));
        year = stoul(s.substr(pos2 + 1, s.size()));
    }
    else if (pos1 = s.find_first_of(",") == string::npos) {
        pos1 = s.find_first_of("/");
        pos2 = s.find_last_of("/");
        str_to_month(s, pos1);
        day = stoul(s.substr(pos1 + 1, pos2));
        year = stoul(s.substr(pos2 + 1, s.size()));
    }
    else if (pos1 = s.find_first_of("/") == string::npos) {
        pos1 = s.find_first_of(" ");
        pos2 = s.find_last_of(",");
        str_to_month(s, pos1);
        day = stoul(s.substr(pos1 + 1, pos2));
        year = stoul(s.substr(pos2 + 1, s.size()));
    }
    else
    {
        day = month = year = 0;
    }
}

Date::~Date()
{
}

inline void Date::str_to_month(string& s, string::size_type& pos1)
{
    if (s.substr(0, pos1) == "Jan" || s.substr(0, pos1) == "January") {
        month = 1;
    }
    else if (s.substr(0, pos1) == "Feb" || s.substr(0, pos1) == "February") {
        month = 2;
    }
    else if (s.substr(0, pos1) == "Mar" || s.substr(0, pos1) == "March") {
        month = 3;
    }
    else if (s.substr(0, pos1) == "Apr" || s.substr(0, pos1) == "April") {
        month = 4;
    }
    else if (s.substr(0, pos1) == "May" || s.substr(0, pos1) == "May") {
        month = 5;
    }
    else if (s.substr(0, pos1) == "Jun" || s.substr(0, pos1) == "June") {
        month = 6;
    }
    else if (s.substr(0, pos1) == "Jul" || s.substr(0, pos1) == "July") {
        month = 7;
    }
    else if (s.substr(0, pos1) == "Aug" || s.substr(0, pos1) == "August") {
        month = 8;
    }
    else if (s.substr(0, pos1) == "Sept" || s.substr(0, pos1) == "September") {
        month = 9;
    }
    else if (s.substr(0, pos1) == "Oct" || s.substr(0, pos1) == "October") {
        month = 10;
    }
    else if (s.substr(0, pos1) == "Nov" || s.substr(0, pos1) == "November") {
        month = 11;
    }
    else if (s.substr(0, pos1) == "Dec" || s.substr(0, pos1) == "December") {
        month = 12;
    }
    else {
        month = stoul(s.substr(0, pos1));
    }
}

std::ostream& operator<< (std::ostream& os,const Date& d)
{
    os << d.getYear() << "-" << d.getMonth() << "-" << d.getDay();
    return os;
}

#endif // !DATE_H_

练习14.6

ostream& operator<<(ostream& os, const Sales_data& it) {
    os << it.isbn() << " " << it.units_sold << " " << it.revenue;
    return os;
}

练习14.7

ostream& operator<<(ostream& os, const String& s)
{
    auto sl = s.begin();
    while (sl != s.end()) os << *(sl++);
    return os;
}

练习14.8

std::ostream& operator<< (std::ostream& os,const Date& d)
{
    os << d.getYear() << "-" << d.getMonth() << "-" << d.getDay();
    return os;
}

练习14.9

istream & operator>>(istream& is, Sales_data& it) {
    is >> it.bookNo >> it.units_sold >> it.revenue;
    if (!is)
        it = Sales_data();
    return is;
}

练习14.10

(a)

0-201-99999-9 10 24.95
0-201-99999-9 10 24.95

(b)

10 24.95 0-210-99999-9
10 24 0.95

练习14.11

没有输入检查,什么也不会发生

练习14.12

std::istream& operator>> (std::istream& is, Date& d)
{
    is >> d.year >> d.month >> d.day;
    if (!is) {
        std::string s = "";
        d = Date(s);
    }
    return is;
}

练习14.13

还应该支持operator-运算符,因此也应该支持operator-=复合运算符

Sales_data& operator-=(const Sales_data& rhs) {
    units_sold -= rhs.units_sold;
    revenue -= rhs.revenue;
    return *this;
}

Sales_data operator-(Sales_data& lhs, Sales_data& rhs) {
    Sales_data sum = lhs;
    sum -= rhs;
    return sum;
}

练习14.14

因为operator+=不需要创建临时空间,所以调用operator+=比其它方法更奏效

练习14.15

不是,因为Date类对于类对象的+-计算会产生二义性

练习14.16

StrBlob类,StrBlobPtr类

inline bool operator==(const StrBlob& lhs, const StrBlob& rhs)
{
    return *lhs.data == *rhs.data;
}

inline bool operator!=(const StrBlob& lhs, const StrBlob& rhs)
{
    return !(lhs==rhs);
}

// named equality operators for StrBlobPtr
inline
bool operator==(const StrBlobPtr &lhs, const StrBlobPtr &rhs)
{
    auto l = lhs.wptr.lock(), r = rhs.wptr.lock();
    // if the underlying vector is the same 
    if (l == r) 
        // then they're equal if they're both null or 
        // if they point to the same element
        return (!r || lhs.curr == rhs.curr);
    else
        return false; // if they point to difference vectors, they're not equal
}

inline
bool operator!=(const StrBlobPtr &lhs, const StrBlobPtr &rhs)
{
    return !(lhs==rhs); 
}

// named equality operators for StrBlobPtr
inline
bool operator==(const ConstStrBlobPtr& lhs, const ConstStrBlobPtr& rhs)
{
    auto l = lhs.wptr.lock(), r = rhs.wptr.lock();
    // if the underlying vector is the same 
    if (l == r)
        // then they're equal if they're both null or 
        // if they point to the same element
        return (!r || lhs.curr == rhs.curr);
    else
        return false; // if they point to difference vectors, they're not equal
}

inline
bool operator!=(const ConstStrBlobPtr& lhs, const ConstStrBlobPtr& rhs)
{
    return !(lhs==rhs);
}

StrVec类

bool operator==(const StrVec& lhs, const StrVec& rhs)
{
    if (lhs.size() != rhs.size()) {
        return false;
    }
    else {
        for (auto l_iter = lhs.begin(),r_iter = rhs.begin(); l_iter != lhs.end(); ++l_iter, ++r_iter) {
            if (*l_iter != *r_iter) {
                return false;
            }
        }
    }
    return true;
}
inline bool operator!=(const StrVec& lhs, const StrVec& rhs)
{
    return !(lhs==rhs);
}

String类

inline bool operator==(const String& lhs, const String& rhs)
{
    if (lhs.size() != rhs.size()) {
        return false;
    }
    else {
        for (auto l_iter = lhs.begin(), r_iter = rhs.begin(); l_iter != lhs.end(); ++l_iter, ++r_iter) {
            if (*l_iter != *r_iter) {
                return false;
            }
        }
    }
    return true;
}
inline bool operator!=(const String& lhs, const String& rhs)
{
    return !(lhs == rhs);
}

练习14.19

inline bool operator==(const Date& lhs, const Date& rhs)
{
    return lhs.year==rhs.year&& lhs.month == rhs.month && lhs.day == rhs.day;
}

inline bool operator!=(const Date& lhs, const Date& rhs)
{
    return !(lhs == rhs);
}

练习14.20

Sales_data& operator+=(const Sales_data& rhs) {
        units_sold += rhs.units_sold;
        revenue += rhs.revenue;
        return *this;
    }

Sales_data operator+(Sales_data& lhs, Sales_data& rhs) {
    Sales_data sum = lhs;
    sum += rhs;
    return sum;
}

练习14.21

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& operator+=(const Sales_data& rhs) {
        const Sales_data tmp = *this;
        *this = tmp + rhs;
        return *this;
    }

operator+=运算符调用operator+运算符前需要创建临时内存空间

练习14.22

Sales_data& Sales_data::operator=(string& s)
{
    bookNo = s;
    units_sold = 0;
    revenue = 0;
}

练习14.23

inline StrVec& StrVec::operator=(std::initializer_list<std::string> il)
{
    auto newdata = alloc_n_copy(il.begin(), il.end());
    free();
    elements = newdata.first;
    first_free = cap = newdata.second;
    return *this;
}

练习14.24

Date类不需要实现拷贝赋值和移动赋值运算符,因为Date类中只含有三个int变量,默认的浅拷贝就能满足要求。

inline Date& Date::operator=(const Date& d)
{
    year = d.year;
    month = d.month;
    day = d.day;
}

inline Date& Date::operator=(Date&&d)
{
    year = d.year;
    month = d.month;
    day = d.day;
}

练习14.25

还应该定义赋值运算符,参数为string,将date作为一个字符串赋值给Date类。

inline Date& Date::operator=(string&s)
{
    string::size_type pos1, pos2;
    if (pos1 = s.find_first_of(",/") == string::npos) {
        pos1 = s.find_first_of(" ");
        pos2 = s.find_last_of(" ");
        str_to_month(s, pos1);
        day = stoul(s.substr(pos1 + 1, pos2));
        year = stoul(s.substr(pos2 + 1, s.size()));
    }
    else if (pos1 = s.find_first_of(",") == string::npos) {
        pos1 = s.find_first_of("/");
        pos2 = s.find_last_of("/");
        str_to_month(s, pos1);
        day = stoul(s.substr(pos1 + 1, pos2));
        year = stoul(s.substr(pos2 + 1, s.size()));
    }
    else if (pos1 = s.find_first_of("/") == string::npos) {
        pos1 = s.find_first_of(" ");
        pos2 = s.find_last_of(",");
        str_to_month(s, pos1);
        day = stoul(s.substr(pos1 + 1, pos2));
        year = stoul(s.substr(pos2 + 1, s.size()));
    }
    else
    {
        day = month = year = 0;
    }
}

练习14.26

StrBlob类

inline std::string& StrBlob::operator[](size_t n)
{
    check(n, "out of range");
    return data->at(n);
}
inline const std::string& StrBlob::operator[](size_t n) const
{
    check(n, "out of range");
    return data->at(n);
}

StrBlobPtr类

inline std::string& StrBlobPtr::operator[](size_t n)
{
    auto ret=check(n, "out of range");
    return (*ret)[n];
}

inline const std::string& StrBlobPtr::operator[](size_t n) const
{
    auto ret = check(n, "out of range");
    return (*ret)[n];
}

StrVec类

inline std::string& StrVec::operator[](size_t n)
{
    if (size() > n && n >= 0)return *(elements + n);
}
inline const std::string& StrVec::operator[](size_t n) const
{
    if (size() > n && n >= 0)return *(elements + n);
}

String类

char& operator[](size_t n) { return elements[n]; };
const char& operator[](size_t n)const { return elements[n]; };

练习14.27

inline StrBlobPtr& StrBlobPtr::operator++()
{
    check(curr, "increment past out end of StrBlobPtr");
    ++curr;
    return *this;
}
inline StrBlobPtr StrBlobPtr::operator++(int)
{
    StrBlobPtr ret = *this;
    ++*this;
    return ret;
}

inline StrBlobPtr& StrBlobPtr::operator--()
{
    --curr;
    check(curr, "increment past begin end of StrBlobPtr");
    return *this;
}

inline StrBlobPtr StrBlobPtr::operator--(int)
{
    StrBlobPtr ret = *this;
    --* this;
    return ret;
}

练习14.28

inline StrBlobPtr& StrBlobPtr::operator+=(size_t n)
{
    curr += n;
    check(curr, "increment past out end of StrBlobPtr");
    return *this;
}

inline StrBlobPtr StrBlobPtr::operator+(size_t n) const
{
    StrBlobPtr ret = *this;
    ret += n;
    return ret;
}

inline StrBlobPtr& StrBlobPtr::operator-=(size_t n)
{
    curr -= n;
    check(curr, "increment past begin end of StrBlobPtr");
    return *this;
}

inline StrBlobPtr StrBlobPtr::operator-(size_t n) const
{
    StrBlobPtr ret = *this;
    ret -= n;
    return ret;
}

练习14.29

递增和递增需要改变对象元素,因此不定义const版本

练习14.30

inline std::string& StrBlobPtr::operator*() const
{
    auto p = check(curr, "dereference past end");
    return (*p)[curr];
}

inline std::string* StrBlobPtr::operator->() const
{
    return &this->operator*();
}


inline const std::string& ConstStrBlobPtr::operator*() const
{
    auto p = check(curr, "dereference past end");
    return (*p)[curr];
}
inline const std::string* ConstStrBlobPtr::operator->() const
{
    return &this->operator*();
}

练习14.31

StrBlobPtr没有动态分配的内存,因此不需要自定义的析构函数,又由三五法则可知不需要定义拷贝构造函数和赋值运算符

练习14.32

class StrBlobPtr_pointer
{
public:
    StrBlobPtr_pointer() = default;
    StrBlobPtr_pointer(StrBlobPtr* p) : pointer(p) { }

    StrBlobPtr& operator *() const;
    StrBlobPtr* operator->() const;

private:
    StrBlobPtr* pointer = nullptr;
};

StrBlobPtr&
StrBlobPtr_pointer::operator *() const
{
    return *(this->pointer);
}

StrBlobPtr*
StrBlobPtr_pointer::operator ->() const
{
    return &this->operator*();
}

int main(int argc,char*argv[]) {
    StrBlob sb{ "hello", "world" };
    StrBlobPtr iter = sb.begin();
    StrBlobPtr_pointer p(&iter);
    std::cout << p->deref() << std::endl;
}

练习14.33

重载的函数调用运算符和该运算符能接受的运算对象相同,因此最大值为256

练习14.34

struct compInt
{
    const int operator()(const int val1, const int val2, const int val3)const {
        return (val1 ? val2 : val3);
    }
};

int main(int argc,char*argv[]) {
    compInt c;
    std::cout << c(1,2,3) << std::endl;
}

练习14.35

class ScanfString
{
public:
    ScanfString(istream& i ) :is(i){ getline(i, str); }
    string operator()() { 
        return str; 
    }
private:
    istream& is;
    string str;
};

int main(int argc,char*argv[]) {
    ScanfString c(cin);
    std::cout << c() << std::endl;
}

练习14.36

class ScanfString
{
public:
    ScanfString(istream& i ) :is(i){ 
        string s;
        while (i) {
            getline(i, s);
            str.emplace_back(s);
        }
    }
    void operator()() { 
        for_each(str.begin(), str.end(), [&](string& s) {cout << s << endl; });
    }
private:
    istream& is;
    vector<string> str;
};

int main(int argc,char*argv[]) {
    ScanfString c(cin);
    c(); 
}

练习14.37

class CompInt
{
public:
    CompInt(int i ) :comp(i){}
    bool operator()(int i) { 
        return comp == i;
    }
private:
    int comp;
};

int main(int argc,char*argv[]) {
    vector<int> vi{ 0,1,2,3,4,3,4,5 };
    CompInt ci(3);
    replace_if(vi.begin(), vi.end(), ci,10);
    for_each(vi.begin(), vi.end(), [](int& i) {cout << i << " "; });
}

练习14.38

class CompInt
{
public:
    CompInt(size_t l, size_t u) :lower(l), upper(u) {}
    CompInt(size_t c = 0) :lower(c), upper(c) {}
    bool operator()(string &s) { 
        return(s.length() >= lower && s.length() <= upper);
    }
private:
    size_t lower;
    size_t upper;
};



int main(int argc,char*argv[]) {
    map<size_t, size_t> words_len;
    for (size_t i = 1; i < 11; ++i) {
        ifstream ifs(argv[1]);
        CompInt ci(i);
        for (std::string word; ifs >> word;) {
            if (ci(word)) ++words_len[i];
        }
    }  
    for (auto i : words_len) {
        cout << i.first << ":" << i.second << endl;
    }
}

练习14.39

class CompInt
{
public:
    CompInt(size_t l, size_t u) :lower(l), upper(u) {}
    CompInt(size_t c = 0) :lower(c), upper(c) {}
    bool operator()(string &s) { 
        return(s.length() >= lower && s.length() <= upper);
    }
private:
    size_t lower;
    size_t upper;
};



int main(int argc,char*argv[]) {
    map<size_t, size_t> words_len;
    ifstream ifs(argv[1]);
    CompInt ci1(1,9);
    CompInt ci2(10,SIZE_MAX);
    for (std::string word; ifs >> word;) {
        if (ci1(word)) ++words_len[1];
        else if (ci2(word)) ++words_len[10];
    }
    for (auto i : words_len) {
        cout << i.first << ":" << i.second << endl;
    }
}

练习14.40

class compString
{
public:
    compString(size_t s):sz(s){}
    const bool operator()(const string& str1, const string& str2)const {
        return (str1.size() >= str2.size());
    }
    const bool operator()(const string& str)const {
        return str.size() > sz;
    }
private:
    size_t sz;
};

class printStr
{
public:
    void operator()(const string& str)const {
        cout << str << " ";
    }
private:

};


void elimDups(vector<string>& words)
{
    sort(words.begin(), words.end());
    auto end_unique = unique(words.begin(), words.end());
    words.erase(end_unique, words.end());
}

void biggies(vector<string>& words, size_t sz)
{
    elimDups(words);
    compString cs(sz);
    printStr ps;
    stable_sort(words.begin(), words.end(), cs);
    auto wc = stable_partition(words.begin(), words.end(), cs);
    for_each(words.begin(), wc, ps);
}

练习14.41

在某些时候, 使用lamdba更方便。当函数方法不经常使用或不复杂时, 可以使用 lambda, 而当调用函数方法实现较复杂且要被频繁调用则使用类。

练习14.42

int main(int argc, char* argv[])
{
    vector<int> iv;
    for (auto i = 1000; i < 2000; i+=2)
        iv.emplace_back(i);
    cout<<"大于1024的数字有"<<count_if(iv.begin(), iv.end(), bind(std::greater<int>(),_1, 1024))<<""<<endl;

    vector<string> svec = { "pooh", "apple", "banana", "pooh" };
    auto word = find_if(svec.cbegin(), svec.cend(), bind(std::not_equal_to<string>(), _1, "pooh"));
    cout << *word << endl;

    transform(iv.begin(), iv.end(), iv.begin(), bind(std::multiplies<int>(), _1, 2));
    for (auto i : iv) {
        cout << i << " ";
    }
}

练习14.43

int main(int argc, char* argv[])
{
    vector<int> iv{1,2,4,8,16};
    if (any_of(iv.begin(), iv.end(), bind(std::modulus<int>(), 1024, _1))) {
        cout << "给定int值不能被int容器中的所有元素整除" << endl;
    }
    else {
        cout << "给定int值能被int容器中的所有元素整除" << endl;
    }  
}

练习14.44

int main(int argc, char* argv[])
{
    std::map<std::string, std::function<int(int, int)>> binops = {
    {"+", std::plus<int>()},                               
    {"-", std::minus<int>()},                  
    {"/", std::divides<int>()},                          
    {"*", std::multiplies<int>()}, 
    {"%", std::modulus<int>()}                              
    };
    while (true) {
        int n1, n2;
        std::string s;
        std::cin >> n1 >> s >> n2;
        std::cout << binops[s](n1, n2) << endl;
    }
    return 0;
}

练习14.45

    explicit operator string() const { return bookNo; }
    explicit operator double() const { return revenue; }
int main(int argc, char* argv[])
{
    Sales_data s;
    cout << static_cast<string>(s) << endl;
    cout << static_cast<double>(s) << endl;
    return 0;
}

练习14.46

不应该定义上述两种类型转换运算符,因为对于使用者来说理解难度高,应该尽量避免让使用者去进行强制类型转换。应该声明为explicit,避免隐式的强制类型转换

练习14.47

struct Integal {
    operator const int();//返回的类型是const类型
    operator int() const;//不允许对象在函数内被修改
};

练习14.48

应该含有,因为Date类需要进行格式判断,又因为向bool的类型转换通常用在条件部分,因此一般定义成explicit的

练习14.49

class Date
{
    friend std::istream& operator>> (std::istream& , Date& );
    friend bool operator==(const Date& lhs, const Date& rhs);
    friend bool operator!=(const Date& lhs, const Date& rhs);
public:
    Date():day(0),month(0),year(0) {}
    Date(string&);
    Date& operator=(const Date&);
    Date& operator=(Date&&)noexcept;
    Date& operator=(string&);
    ~Date();
    unsigned getYear()const { return year; }
    unsigned getMonth() const { return month; }
    unsigned getDay() const { return day; }
    explicit operator bool() const {
        return 1 <= month && month <= 12 && 1 <= day && day <= month_days[((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) ? 1 : 0][month - 1];
    }
private:
    unsigned year;
    unsigned month;
    unsigned day;
    static vector<vector<int>> month_days;
    void str_to_month(string &str,string::size_type& pos);
};

vector<vector<int>> Date::month_days{ { 31,28,31,30,31,30,31,31,30,31,30,31 } ,{ 31,29,31,30,31,30,31,31,30,31,30,31 } };

练习14.50

struct LongDouble {
    LongDouble (double = 0.0);
    operator double();
    operator float();
};
LongDouble ldObj;
int ex1 = ldObj;          // 在将ldObj转换为int时,类定义的类型转换都无法精准匹配,因此会产生二义性,可能先执行 operator double(), 再进行double到int的转换。也可能调用operator float(),再进行float到int的转换。
float ex2 = ldObj;        // 调用operator float()

练习14.51

会优先调用calc(int),因为doube转int是标准类型转换,而LongDouble转int是用户自定义转换。

练习14.52

struct LongDouble {
    LongDouble operator+ (const SmallInt&);
};
LongDouble operator+(LongDouble&, double);
SmallInt si;
LongDouble ld;
ld = si + ld;//没有与这些操作数匹配的+运算符,这是因为上面定义的两个操作符都不够精确 
ld = ld + si;//C++ LongDouble LongDouble::operator+(const SmallInt &)

练习14.53

SmallInt s1;
double d = s1 + 3.14;

不合法,因为s1可以隐式转换为int型,而内置operator+支持int和double的加法,或者将double类型3.14转换为int再转换为SmallInt进行operator+为两个SmallInt的加法,存在二义性

改为

int main(int argc, char* argv[])
{
    SmallInt s1;
    double d = s1 + SmallInt(3.14);
    return 0;
}
原文地址:https://www.cnblogs.com/GodZhuan/p/14022397.html