核心简记
重载运算符是有特殊名称的函数,有返回类型、参数列表、函数体:关键字operator+要定义的符号。参数与运算符作用的运算对象数量一样多,除了重载调用运算符,不能有默认实参。如果运算符函数是成员函数,则第一个运算对象绑定到隐式的this上。
运算符函数,或者是类的成员,或者至少含有一个类类型的参数。意味着不能更改内置类型的运算符。
既是一元又是二元的都能重载,根据参数数量自动判断。
运算符的优先级与结合律不变。
|
|
示例:
重载应该与内置意义一致:
- io操作,定义位移使其io一直
- 检查相等,定义==,通常也有!=
- 有比较操作,定义<,同样应该定义其它。
- 返回类型与内置应该兼容。
成员还是非成员:
- = [] () -> 必须是成员
- 复合一般是成员,不是必须
- 改变对象状态或与给定类型密切相关的,如++ – *解引用,应该是成员。
- 具有对称性质的运算符,如算数、相等、关系、位。通常为了左右参数可通过自动转化而通用,因此非成员
如s+”” 若是成员+改成 “”+s则不正确。因为是先定+的意义,再转化类型,这里+的意义没有找到合适的函数。
当对象为const时,内部成员的成员也不可修改,直接不可,用成员函数的话会要求为const函数,而const的函数中a.f时a也是const的,因此要求f为const。可见
对象是const的,其成员均带const属性,这个属性递归传递!!!
重载运算
输入输出运算符
<<输出
第一个参数是非常量ostream对象的引用。因为向流写东西会改变其状态
第二个参数一般是常量引用
返回流对象引用
输入输出运算符必须是非成员函数
输入
参数1:读取流的引用
参数2:要读入的非常量对象引用
返回流的引用
必须是非成员函数。
输入运算符必须处理输入可能失败的情况,如类型错误、尾等。输出不需要。
当输入流读取成功但格式不符合时,需要手动修改流的状态标出失败信息,通常置于failbit。
算数与关系运算符
通常定义为非成员函数,便于左右侧的转化,因为一般不修改状态,所以为常量引用。
算数运算通常返回临时副本作为结果。
同时定义了复合与算数则用复合实现算数。
定义==准则:
- 如果一个类有判断相等的操作,则定义==。且方便使用库算法
- 定义== 应该能判断重复数据
- 有传递性
- 应该定义!=
关系运算符准则:
- 定义顺序关系
- 应该与==/!=的关系一致,如俩对象!=则俩对象应该有<关系。无法一致时不要定义
赋值运算符
必须是成员函数,如支持列表赋值:
复合运算符不要求是成员,但应该这样。
下标运算符
必须是成员函数
参数类型任意,是[]内传入的。
通常以访问元素的引用作为返回值,左值。最好定义const与非const的,作用范围广。
递增递减运算符
应同时定义前置与后置版本。通常为成员函数。
前置返回对象的引用,后置返回原值。
区分前置后置定义使用一个不使用的int参数:
成员访问运算符
箭头必须是类的成员,解引用通常是成员。
箭头运算符只能改变从哪个对象获取成员:
p->a对于p类型不同,等价于:
函数调用运算符
如果类重载了函数调用运算符,可以像函数一样使用类的对象。可以存储状态。
必须是成员函数,可重载。成为函数对象。
lambda:
lambda是函数对象,编译器生成未命名类与对象,含有重载函数调用。
默认下不可改变捕获的变量,因此默认生成的函数调用是const的。
通过引用捕获时编译器可以直接使用无需存为数据成员,相反,捕获的值要建立数据成员。
functional头文件中定义了大量的表示基本运算、关系等的函数对象,可用于算法库。指针之间<没有意义,但是用标准库less比较指针可以。
可调用对象有:
函数、函数指针、lambda、函数对象。不同的类型可能有一样的调用形式-返回值与参数相同。
functional头文件中的function类可以统一调用形式使用不同的类型。
function类型重载了调用运算符,接受自己的实参将其传递给存好的可调用对象。
不要直接传有重载的函数名,其无法区分,可手动传指针。
使用:
类型转化
转化构造函数与类型转化运算符共同定义了类型转化。
类型转化运算符是类的一种特殊成员函数,负责将类化为其它类型:
operator 向的类型() const;
除了向void都可定义,没有显示的返回类型,没有形参,必须为类的成员函数,一般为const。但要返回指定的类型。
使用:
若a重载了+会有二义性。
定义向bool的转化普遍。但是很容易引起自动转化的冲突和隐式的错误。因此使用显示类型转化符:
explicit operator ….
使用时必须强制转化,不过当用作条件时,显示类型转化会被隐式执行,不必强制。
避免二义
向与从重复:
从与从向与向重复
不要自己定义多种到内置类型的,由编译器自己转化类型最好
不同类型重载冲突:
转化的级别判定只有当同一个类时才有用,类型转化不止一个时,二义性。即使有一个精确匹配。
函数候选集扩大的冲突:
a+b 使用普通函数/成员函数均可。
俩个的作用范围不同,可以重载,但范围有交集,调用时可能冲突。
当左内置右类对象时,选择范围为非成员与内置。
当左为类对象时,范围为内置、非成员、成员。
在选择范围内不要有任何的可行方案冲突。决定调用的版本时,左右参数与其转化在函数可选范围内,不要有冲突
反汇编
debug下不会使用inline。
这次观察下全局构造的位置
ARM64
init-arry:
构造函数被调用处:
通过对linker的分析可以发现,在execve将linker与应用程序都加载了,之后linker解析动态段,加载so后调用所有的init_array。这时初始化全局变量。