c++ primer(第五版)笔记 第十四章 重载运算与类型转换

来源:互联网 发布:移动端js选择时间插件 编辑:程序博客网 时间:2024/05/05 01:10
// 重载运算符: 其函数名由operator关键字和定义的运算符号组成// 其参数数量与该运算符作用的运算对象数量一致// 对于二元运算符来说,左侧运算对象传递给第一个参数,右侧运算对象传递给第二个参数// 除 operator() 外,其他重载运算符都不能含有默认实参// 如果该函数是一个成员函数,则其第一个运算对象绑定到隐式的 this 指针上// 不能被重载的运算符:// 域运算符 ::// 指向成员选择的指针 .*// 成员选择符.// 条件运算符?:// 不应该重载的运算符:可能无法保留运算顺序和短路求值属性// 逻辑与&&// 逻辑或||// 逗号,// 取地址&// 必须定义为成员函数:// 赋值=// 下标[]// 调用()// 成员访问箭头->// 应该定义为成员函数:对象状态的运算符或与给定类型密切相关的运算符// 符合赋值// 递增/碱// 应该定义为普通成员函数:具有对称性的运算符可能转换任意一端的运算对象// 算术// 相等性// 关系// 位运算// 重载输出运算符// 参数一:非常量 ostream 对象的引用// 参数二:常量的引用// 因为第一个参数必须是 ostream 对象,所以非成员函数,// 因为需要输出对象成员,所以友元// 重载输入运算符// 参数一:ostream 对象的引用// 参数二:非常量的引用// 因为第一个参数必须是 iostream 对象,所以非成员函数,// 因为需要输出对象非公有成员,所以友元// 输入运算需要检查错误,并从错误中恢复// 算术运算符// 非成员以允许左右两侧的运算对象互换// 如果定义了复合运算,通常使用复合运算实现// 相等运算符// 通常也定义不相等,实际工作由其中一个实现,另一个调用真正实现// 关系运算符// 定义时,遵循容器关键字的要求// 赋值运算符// 必须为成员函数,必须返回左侧对象的引用// 拷贝赋值// 移动赋值// 针对其它类型的右侧对象的赋值// 下标运算符// 容器类需要通过位置访问时// 返回普通引用// 返回常量对象的常量引用// 递增递减运算符// 通常改变对象状态,建议成员函数// 前置版本operator++()返回引用,改变状态前,需要检查有效性// 后置版本operator++(int) 返回原值,使用前置版本实现,int 参数仅用于区别2个版本,并不参与运算// 成员访问运算符// -> 必须是成员, 必须返回类的指针或自定义了 ->运算的某个类的对象// *一般也是,并且通常都为 const 函数// 函数调用运算符// 定义了此运算符的类对象成为函数对象(function object) 如 lambda// 必须成员函数,若定义多个调用运算,需在参数个数和类型上有所区别// lambda 是函数对象// 编译器将 lambda 翻译成未命名类的未命名对象,在该类中产生一个重载的函数调用运算符// eg.vector<string> words;stable_sort(words.begin(), words.end(), [](const string &a, const string &b){return a.size() < b.size();})// 类似类:class Shortstring{public:bool operator()(const string &a, const string &b) const {return a.size() < b.size();}};// 使用该类重写:stable_sort(words.begin(), words.end(), Shortstring())// 对于通过引用捕获变量时,由程序确认引用对象的存在,无须再产生的类中将其存储为数据成员// 对于值捕获时,必须为其建立成员变量,同时构建构造函数,使用捕获的值来初始化数据成员// eg.vector<string> words;size_t sz = 0;cin >> sz;auto wc = find_if(words.begin(), words.end(), [sz](const string &a){return a.size() >= sz;})// 类似类:class Sizecomp{public:Sizecomp(size_t n):sz(n){}bool operator(const string &a) const {return a.size() >= sz;}private:size_t sz;};// 使用该类重写:auto wc = find_if(words.begin(), words.end(), Sizecomp(sz));// 标准库函数对象 定义于 functional.h// 算术运算符// plus<type>// minus<type>// multiplies<type>// divides<type>// modulus<type>// negate<type>// 关系运算符// equal_to<type>// not_equal_to<type>// greater<type>// greater_equal<type>// less<type>// less_equal<type>// 逻辑运算符// logical_and<type>// logical_or<type>// logical_not<type>// 可调用对象:// 函数,// 函数指针,// lambda,// bind创建的对象,// 重载的函数调用运算符// 函数表(function table),储存指向可调用对象的指针,用 map 实现//加法 普通函数int add(int a, int b){return a + b;}//求余 lambdaauto mod = [](int a, int b){return a % b;};//除法 函数对象类class divide{public:int operator()(int a, int b){return a / b;}};//函数表map< string, int(*)(int, int)> binops;//普通函数直接插入表中binops.insert({"+", add});//对于 lambda 和 类,明显不同于表需要的值类型// function 模板类, 定义于 functional.hfunction<int(int, int)> f1 = add;function<int(int, int)> f2 = [](int a, int b){return a % b;};function<int(int, int)> f3 = divide();//改写函数表类型map<string, function<int( int, int)>> binops{{"+", add},{"-", std::minus<int>()},{"*", [](int a, int b){return a * b;}},{"/", divide()},{"%", mod}};//调用binops["+"](10,5);binops["-"](10,5);binops["*"](10,5);binops["/"](10,5);binops["%"](10,5);//使用 function 时,注意重载函数的二义性// 类的类型转换// 特殊的成员函数// operator type() const;// type 表示某种类型,只要该类型能作为函数的返回类型.因此不能是数组或函数,可以是指针或引用// 没有显式的返回类型,也没有形参,通常不改变转换对象的内容,一般为 constclass SmallInt{public:SmallInt( int i = 0):val(i){if(i < 0 || i > 255)throw std::out_of_range("wrong smallint value!");}operator int() const {return val;}private:std::size_t val;}SmallInt si;si = 1;//1 转换为 SmallInt 类型,然后operator=si + 3;//si 转换为 intsi + 3.14;//si 转换为 int,再转换为 double如果 istream::cin 定义了 operator bool() 会发生什么?int n = 5;cin << n;//合法,cin 隐式转换为 bool,然后再提升为 int, 然后位运算左移 n 位.// 为了避免上面的问题,c++11 引入显式类型转换运算符class SmallInt{public:SmallInt( int i = 0):val(i){if(i < 0 || i > 255)throw std::out_of_range("wrong smallint value!");}explicit operator int() const {return val;}private:std::size_t val;}si = 1;//1 通过构造转换为 SmallInt 类型,然后operator=si + 3;//错误,禁止隐式转换static_cast<int>(si) + 3;//显式请求转换// 表达式用于条件时,显式的转换会自动执行// 即 if(si + 3) 正确,// 在 while, if, for, !, ||, &&, ?: 条件部分都会自动发生// 避免二义性,// 如:A类定义了B类型参数的构造,B类定义了A类型的转换运算符// 又如:定义了2个转换对象都为算术类型的转换运算符

0 0