zoukankan      html  css  js  c++  java
  • 第十四章 重载运算与类型转换

    14.1

    不同点:重载运算符至少有一个操作数是类类型,而且对于部分运算符它无法保留求值顺序或短路求值属性

    相同点:对于一个重载运算符来说,其优先级和结合律与对应的内置运算符保持一致

    14.2

     1 #include <iostream>
     2 #include <vector> 
     3 #include <string>
     4  
     5 using namespace std;
     6 
     7 class Sales_data { 
     8     friend istream &operator>>(istream &is, Sales_data&);
     9     friend ostream &operator<<(ostream &os, Sales_data&);
    10 public:
    11     //构造函数 
    12     Sales_data() = default;
    13     //重载运算符
    14     Sales_data &operator+=(const Sales_data&);
    15 private:
    16     string bookNo;                //书的ISBN 
    17     unsigned units_sold = 0;    //售出的本数 
    18     double revenue = 0.0;        //销售额
    19 };
    20 
    21 istream &operator>>(istream &is, Sales_data &book)
    22 {
    23     is >> book.bookNo >> book.units_sold >> book.revenue;
    24     return is;
    25 }
    26 
    27 ostream &operator<<(ostream &os, Sales_data &book)
    28 {
    29     os << book.bookNo << " " << book.units_sold << " " << book.revenue;
    30     return os;
    31 }
    32 
    33 Sales_data &Sales_data::operator+=(const Sales_data &rhs)
    34 {
    35     units_sold += rhs.units_sold;
    36     revenue += rhs.revenue;
    37     return *this;
    38 }
    39 
    40 Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs)
    41 {
    42     Sales_data total = lhs;
    43     total += rhs;
    44     return total;
    45 }
    46 
    47 
    48 int main()
    49 {
    50     Sales_data a;
    51     cin >> a;
    52     Sales_data b, c;
    53     b = a;
    54     c = a + b;
    55     cout << a << endl << b << endl << c << endl;
    56     return 0;
    57 }
    View Code

    14.3

    (a):使用了内置版本的==,比较两个指针

    (b):使用了string重载的==

    (c):使用了vector重载的==

    (d):使用了string重载的==

    14.4

    应该是类的成员:%=、++、->、()

    14.9

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

    14.10

    (a):正确

    (b):由于const char*不能转换为double,所以读取操作失败,对象将被赋予默认的状态

    14.11

    存在错误,这个定义函数没有实现对输入数据正确性的判断

    如果给定上个练习的(b),则revenue的值将是未定义的

    14.13

    可以定义一个减法运算符

    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 sub = lhs;  
        sub -= rhs;  
        return sub;  
    } 
    

    14.14

    使用operator+=来定义operator+比较好,可以省去重复完成operator+中做的事

    14.20

    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 += rhs;
    	return sum;
    } 
    

    14.21

    Sales_data &Sales_data::operator+=(const Sales_data &rhs)
    {
    	units_sold = units_sold + rhs.units_sold;
    	revenue = 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;
    } 
    

    缺点:可读性较差

    14.22

    Sales_data &Sales_data::operator=(const string &s)
    {
    	bookNo = 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.26

    class StrVec  
    {  
    public:  
        string &operator[](size_t n) { return elements[n]; }  
        const string &operator[](size_t n) const { return elements[n]; }  
    };
    

    14.27

    class StrBlobPtr {
    public:
    	//前置运算符 
    	StrBlobPtr &operator++();
    	StrBlobPtr &operator--();
    	//后置运算符
    	StrBlobPtr &operator++(int);
    	StrBlobPtr &operator--(int); 
    }; 
    
    StrBlobPtr &StrBlobPtr::operator++()  
    {  
        check(curr, " increment past end of StrBlobPtr ");  
        ++curr;  
        return *this;  
    }  
    StrBlobPtr &StrBlobPtr::operator--()  
    {  
        --curr;  
        check(-1, " decrement past begin of StrBlobPtr ");    
        return *this;  
    }  
    
    StrBlobPtr StrBlobPtr::operator++(int)  
    {  
        StrBlobPtr ret = *this;  
        ++*this;  
        return ret;  
    }  
    StrBlobPtr StrBlobPtr::operator--(int)  
    {  
        StrBlobPtr ret = *this;  
        --*this;  
        return ret;  
    } 
    

    14.29

    对于++和--运算符,无论是前缀版本还是后缀版本,都会改变调用对象本身的值,因此是不能定义成const的。

    14.31

    对于StrBlobPtr类,它的数据成员有两个,分别是weak_ptr<vector<string>>和size_t类型的,前者定义了自己的拷贝构造函数、赋值运算符和析构函数,后者是内置类型。所以该类不需要定义析构函数,从而相应的拷贝构造函数、赋值运算符也不需要定义,使用相应的合成版本即可。

    14.33

    与相应的函数调用运算符的形参数目一致

    14.34

    #include <iostream>
     
    using namespace std;
    
    class A {
    public:
    	string operator()(size_t i, string s1, string s2) const 
    	{
    		return i % 2 ? s1 : s2;
    	}
    };
    
    int main()
    {
    	A a;
    	string s = a(1, "odd", "even");
    	cout << s << endl; 
        return 0;
    }
    

    14.35

    #include <iostream>
    #include <vector> 
    #include <string>
     
    using namespace std;
    
    class A {
    public:
    	A(istream &in = cin): is(in) {}
    	string operator()()
    	{
    		string line;
    		getline(is, line); 
    		if (!is)
    			line = "";
    		return line;
    	}
    private:
    	istream &is;
    };
    
    int main()
    {
    	A a;
    	cout << a() << endl;
        return 0;
    }

     

    14.36

    int main()
    {
    	A a;
    	vector<string> vec;
    	string s = a();
    	while (s != "") {
    		vec.push_back(s);
    		s = a();
    	}
    	for (auto &i : vec)
    		cout << i << endl;
        return 0;
    }
    

    14.37

    #include <iostream>
    #include <vector> 
    #include <string>
    #include <list>
    #include <algorithm>
     
    using namespace std;
    
    class A {
    public:
    	A() = default;
    	A(int i): val(i) {}
    	bool operator()(const int &a)
    	{
    		return val == a;
    	}
    private:
    	int val;
    };
    
    int main()
    {
    	list<int> lst = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    	//将lst中值为2的元素替换为22 
    	replace_if(lst.begin(), lst.end(), A(2), 22); 
        return 0;
    }
    

    14.38

    #include <iostream>
    #include <fstream>
    #include <vector> 
    #include <string>
    #include <list>
    #include <algorithm>
     
    using namespace std;
    
    class A {
    public:
    	int operator()(const string &s)
    	{
    		return s.size();
    	}
    };
    
    int main()
    {
    	ifstream in("data.txt");
    	int arr[30] = {0};
    	A a;
    	string word;
    	while (in >> word) {
    		int pos = a(word);
    		++arr[pos];
    	}
    	for (int i = 1; i != 11; ++i)
    		cout << "长度为" << i << "的单词的个数是:" << arr[i] << endl;
    	return 0; 
    }
    

    14.39

    #include <iostream>
    #include <fstream>
    #include <vector> 
    #include <string>
    #include <list>
    #include <algorithm>
     
    using namespace std;
    
    class A {
    public:
    	bool operator()(const string &s)
    	{
    		if (s.size() < 10)
    			return true;
    		return false;
    	}
    };
    
    int main()
    {
    	ifstream in("data.txt");
    	int num1 = 0, num2 = num1;
    	A a;
    	string word;
    	while (in >> word) {
    		bool flag = a(word);
    		if (flag)	++num1;
    		else ++num2;
    	}
    	cout << "长度小于10的单词的个数是:" << num1 << endl;
    	cout << "长度大于10的单词的个数是:" << num2 << endl;
    	return 0; 
    }
    

    14.40

    class A {
    public:
    	bool operator()(const string &s1, const string &s2)
    	{
    		return s1.size() < s2.size();
    	}
    }; 
    
    class B {
    public:
    	A(int i): sz(i) {} 
    	bool operator()(const string &s)
    	{
    		return s.size() >= sz;
    	}
    private:
    	int sz;
    };
    
    class C {
    public:
    	void operator()(const string &s)
    	{
    		cout << s << " ";
    	}
    };
    
    void biggies(vector<string> &words, vector<string>::size_type sz)
    {
    	stable_sort(words.begin(), words.end(), A());
    	auto wc = find_if(words.begin(), words.end(), B(sz));
    	for_each(wc, words.end(), C());
    }
    

    14.41

    在C++11中,lambda是通过匿名的函数对象来实现的,因此我们可以把lambda看作是对函数对象在使用方式上进行的简化。当代码需要一个简单的函数,并且这个函数并不会在其他地方被使用时,就可以使用lambda来实现,此时它所起的作用类似于匿名函数。但如果这个函数需要多次使用,并且它需要保存某些状态的话,使用函数对象更合适一些。

    即,lambda表达式方便创建、使用,不需要额外的为调用对象声明类;在一次性需要使用函数对象时使用lambda,在多次需要使用到相同的函数对象时使用类。

    14.42

    	vector<int> ivec{520, 1020, 1030};
    	vector<string> svec{"pooh", "pooh", "pool", "pooh", "poow"};
    	auto num = count_if(ivec.begin(), ivec.end(), bind(greater<int>(), _1, 1024));
    	auto it = find_if(svec.begin(), svec.end(), bind(not_equal_to<string>(), _1, "pooh"));
    	transform(ivec.begin(), ivec.end(), ivec.begin(), bind(multiplies<int>(), _1, 2));
    

    14.43

    int main()
    {
    	vector<int> ivec{520, 1020, 1030};
    	int div;
    	cin >> div;
    	//返回取余结果为0的数的个数 
    	int num = count_if(ivec.begin(), ivec.end(), bind(modulus<int>(), _1, div));
    	if (!num)
    		cout << "全部可整除" << endl;
    	else	cout << "不能全部被整除" << endl; 
    	return 0; 
    }
    

    14.44

    #include <iostream>
    #include <map>
    #include <functional>
    
    using namespace std;
    
    map<string, function<int (int, int)>> binops;
    
    class multiply {
    public:
    	int operator()(int a, int b) const { return a * b; }
    };
    
    int add(int a, int b)
    {
    	return a + b;
    }
    
    auto divide = [](int a, int b) { return a / b; };
    
    void func()
    {
    	binops.insert({"+", add});
    	binops.insert(make_pair("-", minus<int>()));
    	binops.insert(pair<string, function<int (int, int)>>("*", multiply()));
    	binops.insert(map<string, function<int (int, int)>>::value_type("/", divide));
    	binops.insert({"%", [](int a, int b) { return a % b; }});
    }
    
    int main()
    {
    	func();
    	cout << "请按照此形式(如:a + b)输入计算表达式:
    ";
    	int a, b;
    	string s;
    	while (cin >> a >> s >> b) {
    		cout << binops[s](a, b) << endl;
    		cout << "请按照此形式(如:a + b)输入计算表达式:
    ";
    	}
    	return 0;
    } 

    14.45

    	operator string() const { return bookNo; }
    	operator double() const { return revenue; }
    

    14.46

    Sales_data不应该定义这两种类型转换运算符,因为对于类来说,它包含三个数据成员:bookNo,units_sold和revenue,只有三者在一起才是有效的数据。但是如果确实想要定义这两个类型转换运算符的话,应该把它们声明成explicit的,这样可以防止sales_data 在默写情况下被默认转换成string或double类型,这有可能导致意料之外的运算结果。

    14.47

    operator const int();:将对象转换成const int,没有意义,因为只有在接受const int值的地方才能够使用

    operator int() const:将对象转换成int值,const 表示转换时不会修改对象数据

    14.50

    对于int ex1 = ldObj;,它需要把LongDouble类型转换成int类型,但是LongDouble并没有定义对应的类型转换运算符,因此它会尝试使用其他的来进行转换。题中给出的两个都满足需求,但编译器无法确定那一个更合适,因此会产生二义性错误。

    对于float ex2 = ldObj;,它需要把LongDouble转换成float类型,而我们恰好定义了对应的类型转换运算符,因此直接调用operator float()即可。

    14.51

    这里会优先调用void calc(int);

    因为double转换为int是标准类型转换,而转换为LongDouble则是转换为用户自定义类型,实际上调用了转换构造函数,因此前者优先。

    14.52

    ans1:

    对于ld=si+ld,由于LongDouble不能转换为SmallInt,因此Smallint的成员operator+和friend operator都不可行。

    由于Smallint不能转换为LongDouble,LongDouble的成员operator+和非成员operator+也都不可行。

    由于SmallInt可以转换为int, LongDouble了可以转换为float和double,所以内置的operator+(int, float)和operator+(int, double)都可行,会产生二义性。

    对于ld=ld+si,类似上一个加法表达式,由于Smallint不能转换为double,LongDouble也不能转换为SmallInt,因此SmallInt的成员operator+和两个非成员operator+都不匹配。

    LongDouble的成员operator+可行,且为精确匹配。
    SmallInt可以转换为int,longDouble可以转换为float和double,因此内置的operator+(float, int)和operator(double, int)都可行。但它们都需要类型转换,因此LongDouble的成员operator+优先匹配。

    ans2:

    ld=si+ld;二义性,si将转换为int,但ld可以转换为double也可以使float

    ld=ld+si;精确匹配LongDouble operator+(const SmallInt &);,虽然使用后面的也可以,但是需要转换,所以前者更好

    14.53

    内置的operator+(int, double)是可行的,而3.14可以转换为int,然后再转换为SmallInt,所以SmallInt的成员operator+也是可行的。两者都需要进行类型转换,所以会产生二义性。改为:double d = s1 +Smallint(3.14);即可。

  • 相关阅读:
    Andriod 简介
    Java 记录日志
    Java 国际化
    Java 正则表达式的使用
    Java 日期、时间类,日期、时间的格式化
    Java Random类、ThreadLocalRandom类
    Java Math类、BigDecimal类、NumberFormat类、浮点数的精确度问题
    Java String类、StringBuilder类、StringBuffer类
    Java System类、RunTime类、Object类、垃圾回收
    span 右浮动折行 解决ie6/7中span右浮动折行问题
  • 原文地址:https://www.cnblogs.com/xzxl/p/7768689.html
Copyright © 2011-2022 走看看