- 关于运算符重载
- 不可重载的运算符 :: .* . ?: , &
- 赋值(=)下标([ ]) 调用(( ))成员访问箭头(-〉)运算符(相对的解引用 * 也应该是成员函数)必须是成员函数,复合赋值运算符一般来说也应该是成员。改变对象状态的运算符如自增、自减、解引用等通常也应该是成员,对于这些成员运算符函数应该返回所属类的一个对象。
- 具有对称性的运算符可能转换任意一端的运算对象,通常为非成员函数。
- 输入和输出运算符必须是非成员函数
- 关于自增、自减运算符,前置无参,后置有一个虚参
- 关于赋值运算符,可能存在安全风险,其处理方法如前所示,尽可能以swap函数来处理。
- 关于关系运算符一般成对出现。
- 解引用和箭头运算符均无参。箭头运算符永远不能丢掉成员访问这个基本含义,当重载时,可以改变的是箭头从哪个对象当中获取成员,其他用户什么也不能做。
- 函数调用运算符,这个特有名气了,说说优点,可以像函数一样工作。优点是可以有状态。c++11新增的lambda变是以其实现的,但是一个无名的类的函数对象。相应也不能保存状态。但优点是方便。
- lambda
- 如前所说,其在编译器中的底层实现依旧是一个类函数。
- lambda函数的标准形式: [capture](parameters) mutable ->return-type{statement;}
- [capture] 捕捉列表,这在用法上,可以单独捕捉某几个参数,也可以通过[=]以值的方式捕捉所有的外部参数。可以捕捉值,也可能以引用的方式捕捉。另若按值传递,则其在定义函数的那一刻,值已传入函数中,且不会改变的。即若在之后,即合改变了捕捉的外部变量,但前面已定义的lambda函数依旧会使用前值。若需要其跟随外部变量一起变化,需要将其改为引用的传值方式,
#include <iostream> using namespace std; int main() { int i =4; int j = 5; int k = 8 ; auto f=[i,j](){return i+j;}; auto g = [=]()->int{ return i*j*k;}; auto l = [&](){ return ++i*++j*++k; }; auto p=[&i,&j](){i=i+j;j=j-i;}; cout << f()<<" "<<g()<<" "<<l()<<endl; cout << i << " "<<j<<" "<<k<<endl; p(); cout <<i <<" "<<j<<endl; }
- (parameters)参数列表,可省略。
- mutable 默认情况下,lambda函数往往是一个const函数,mutable可以取消其常量性,这在值传入时有用。在引用传入时,无此作用。--可省略
#include <iostream> using namespace std; int main() { int i =4; /*若在此中修改捕捉的i,编译器会报错,在这里要加上mutable修饰符。 auto p= [i](){ i=9; }; */ auto q = [i]()mutable{ i =9; }; }
- -> return-type ,尾置返回类型,可省略
- {statement;}函数主体
- [capture] 捕捉列表,这在用法上,可以单独捕捉某几个参数,也可以通过[=]以值的方式捕捉所有的外部参数。可以捕捉值,也可能以引用的方式捕捉。另若按值传递,则其在定义函数的那一刻,值已传入函数中,且不会改变的。即若在之后,即合改变了捕捉的外部变量,但前面已定义的lambda函数依旧会使用前值。若需要其跟随外部变量一起变化,需要将其改为引用的传值方式,
- c++11标准允许lambda向函数指针转换,前提是函数指针没有任何捕获的变量,且函数指针所示的原型与lambda函数有相同的调用方法。当然,最彻底解决此问题的办法还是标准库中的function<T>类型这样的东西
- 最简单的lambda函数,[]{};
- 类型转换运算符
- 类型转换为隐式执行,故无参,无返回类型。其指类可以转为何种类型
- 在c++11中引进了显示类型转换,确保转换按照用户要求。即用户定义类时可以以explicit 声明,再以static_cast<>进行显示转换,
#include <iostream> using namespace std; struct s{ explicit operator double(){ //显示转换声明 return .23; } }; struct p{ operator bool(){ return true; } }; int main() { s a; cout << static_cast<double>(a)/2; //显示转换 //cout << a/2; if(p()){ //隐式转换 cout << "operator p is true!"; } }
- 所以在使用中一定要避免二义性的类型转换
- 一是类A可以多种方法转为类B,即B可以通过A的构造函数转为A,也可以通过自己operator A()转为A,这会造成二义性
- 避免转换目标是内置算术类型的重载运算符。除了显式地向Bool类型的转换之外,我们应尽量避免定义类型转换函数并尽可能地限制使用。
- 不要再定义接受算术类型的重载运算符。
- 不要定义转换到多种算术类型的类型转换。
- 不要为类同时提供转换目标是算术类型的类型转换,也提供重载的运算符。
c++/c学习笔记 --(6)
最新推荐文章于 2021-07-21 22:10:42 发布