您的位置:首页 > 编程语言 > C语言/C++

读书笔记:C++ primer 5th edition--chapter14.重载运算与类型转换

2016-10-13 00:22 525 查看
part1.基本概念
1.重载运算符函数的参数数量与该运算符作用的运算对象数量一样多。如果一个运算符函数是成员函数,则this绑定到左侧运算对象上。函数的参数数量会比运算对象数量少一个。
2.只能重载已有运算符。不能发明,比如**
3.可以直接调用一个重载的运算符函数
//二者等价
data1 += data2;
data1.operator+=(data2);
4.不应该重载逗号,取地址,逻辑与,逻辑或运算符
5.如果定义了==,也要定义!=
6.如果类包含一个内在的单序比较操作,则定义operator<,当然也要定义其他关系操作
7.成员非成员
1)赋值,下标,调用,和成员访问箭头运算符,解引用,递增递减必须是成员
2)具有对称性的运算符,如算术,相等性,关系,和位运算符,应该是非成员函数
8.当把运算符定义成成员函数时,它的左侧运算对象必须是运算符所属类的一个对象。而string把+定义为非成员函数,只要求两侧至少有一个运算对象是类类型,且能转换成string。

part2.输入输出运算符
1.重载输出运算符
第一个形参是非常量ostream对象的引用,写入流会改变状态,且无法复制
第二个形参是一个常量的引用,避免复制。
还要返回它的ostream形参
ostream &operator<<(ostream &os, const Sales_data &item){
     os << item.isbn()<< “” << XXX…     //不要换行,减少控制
     return os;
}
2.重载输入运算符
输入运算符必须处理输入可能失败的情况,当读取操作发生错误时,输入运算符应该负责从错误中恢复。
istream &operator>>( istream &is, Sales_data &item){
     doulbe price;
     is >> item.bookNo >> item.units_sold >> price;
     if( is )
          xxx
     else
          item = Sales_data(); //输入失败:对象被赋予默认状态
     return is;
}

part3.算术和关系运算符
1.如果定义了算术运算符,一般也会定义一个对应的复合赋值运算符。且用复合赋值运算符来定义算术运算符。
Sales_data
operator+(const Sales_data &lhs, const Sales_data &rhs){
     Sales_data sum = lhs;
     sum += rhs;
     return sum;
}
2.相等运算符,比较所有成员
return lhs.isbn() == rhs.isbn() &&
          lhs.units_sold == rhs.units_sold ;
另外,不等运算符通过==来定义:
return !( lhs == rhs);
3.关系运算符
如果存在唯一一种可靠地<定义,则应该考虑定义<运算符。多个成员一般不要定义。
原则是:如果两个对象时 != 的,那么一个对象应该<另外一个。

part4.其他运算符
1.赋值运算符必须是成员函数
2.下标运算符必须是成员函数,且最好同时定义常量和非常量版本
3.递增和递减运算符,应该同时定义前置版本和后置版本,前置版本返回递增后对象的引用,后置版本返回对象的原值。后置版本接受额外int类型形参作为区分。
4.箭头运算符必须是类成员,且与*不同,箭头运算符不能丢掉成员访问的最基本定义。重载的箭头运算符必须返回类的指针或者自定义了箭头运算符的某个类的对象。
5.函数调用运算符
如果累定义了调用运算符,则该类对象称作函数对象。
函数对象常作为泛型算法的实参。例子见下。
6.lamda是函数对象
class ShorterString{
public:
     bool operator() (const string &s1, const string s2 ) const
     {
          return s1.size() < s2.size();
     }
}
用上述类代替lamda表达式,重写:
stable_sort( words.begin(), words.end(), ShorterString() );
7.标准库定义的函数对象,比如greater<Type>的 usage:
sort( svec.being(), svec.end(), greater< string > () );
甚至可以通过比较指针的内存地址来排序
vector<string * > spVec;
8.可调用对象
1)包括:函数,函数指针,lamda表达式,bind创建的对象,以及重载了函数调用运算符的类。
2)调用形式:int(int, int);不同类型的可调用对象会共享同一种调用形式。
3)可以用map存储指向这些可调用对象的函数表。
4)使用标准库function类型
fucntion<int(int, int) > f1 = add;          //函数指针
fucntion<int(int, int) > f2 = divide();     //函数对象类的对象
cout<< f1(4, 2) << endl;
cout << f2(4,2) << endl;
定义map:
map< string, function<int(int, int)>> binops = {
     {“+”, add},                         //函数指针
     {“-“, std::minus<int>}          //标准库函数对象
     ...
}
binops[“+”](10, 5)
binops[“-“](10, 5)

part5.重载、类型转换与运算符
1.类型转换运算符是类的特殊成员,负责将一个类类型的值转换成其他类型:
operator type () const;
2.面向任意类型,除了void,只要改类型能作为函数的返回类型。所以不能是数组或者函数类型。
3.最好加入explicit
4.避免二义性的类型转换,略过
5.函数匹配:当运算符函数出现在表达式中的时候,无法通过调用的形式区分当前调用时成员函数与否。
a sym b could be:
a.operater sym(b)
operatator sym(a,b) 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++ 重载