运算符函数的格式:#表示运算符 O表示运算符对象 []代表返回值不确定
在C++中 << >> 运算符不光是按位左移、按位右移,同时还是cout该类的输出运算符 cin该类的输入运算符
输出运算符:
cout << 10 << endl;
Test t;
cout << t << t2 << endl;
由于 << 运算符的调用者是cout对象,我们是无法在该对象的类中去设计一个输出运算符的成员函数,所以只能实现 << 运算的全局函数
ostream& operator<<(ostream& os,const O& t)
{
return os << t.x << t.y;
}
输入运算符:
cin >> num;
cin >> t1 >> t2;
istream& operator>>(istream& is,O& t)
{
return is >> t.x >> t.y;
}
注意:
1、由于输出、输入是可以连续进行的,所以返回值还应该是ostream、istream引用
2、因为无法在ostream、istream中重载运算符成员函数,所以<< >>只能重载成全局函数
3、如果在重载全局函数中使用到自己类中私有的成员变量,需要声明为友元函数
4、输出运算符函数中,第二个参数一定要加const,而输入运算符函数中不能加
单目:++/-- ! ~ - * & sizeof
成员函数: ~ ! -
const int num;
~0; ~num; true
~num = 10; false
O O::operator~(void)const
{
return O(~x,~y);
}
注意:运算对象可以具备常属性,因此需要是常函数,运算结果只是一个临时值,并且是右值
全局函数:
O operator~(const O& a)
{
return O(~a.x,~a.y);
}
C++的前后自变左右值问题:
能位于赋值运算符= 左边的就是左值,反之为右值
有名称、可以获取到存储地址的称为左值,反之为右值
C++前自变:++num = 10; // 成功 num=10
直接修改原对象,在原对象基础上实现自变,然后将原对象的引用返回,所以操作和返回的一直是原对象,是左值
C++后自变:num++ = 10; // 报错
先将原对象的数据存储到临时变量中,接着在原对象基础上自变,然后把临时变量以只读方式返回,并且该临时变量执行语句结束后立即销毁了,无法访问,因此结果是右值
++num++ // 后自变优先级更高,报错
(++num)++ // 先前自变为左值,成功
注意:C语言中,无论前后自变,结果都是右值
成员函数:
O& O::operator++(void)
{
x++,y++;
return *this;
}
全局函数:
O& operator++(O& a)
{
a.x++,a.y++;
return a;
}
哑元:在参数列表末尾增加一个不使用且无形参名的int哑元类型,唯一目的就是用于区分是前自变还是后自变
成员函数:
O O::operator++(int)
{
return O(x++,y++);
}
全局函数:
O operator++(O& a,int)
{
return O(a.x++,a.y++);
}
* -> () [] new delete
想让一个类对象当成数组一样使用,可以考虑重载下标运算符,例如:vector等
可以考虑在下标重载函数中做非法下标的判断,让下标的使用更安全
重载此运算符可以让一个类对象当做函数一样使用
注意:()\[] 均不能实现为全局运算符函数,只能实现成员函数(C++全局中已经有类似的函数实现,所以不让实现)
= 赋值运算符函数也不能实现为全局函数,因为类内本身一定有一个=赋值运算符成员函数
重载这两个运算符可以让类对象像指针一样使用,智能指针就是通过重载这俩运算符从而像使用指针一样的类
void* operator new(size_t size)
C++语法要求重载new运算符的参数必须为size_t,编译器会帮助计算出要申请的字节数并传递,返回值必须为void*,编译器会帮助转换成对应的类型指针返回
void operator delete(void* ptr)
C++语法要求重载delete的参数必须为void*,编译器帮助转换成void*传递
注意: new、delete的成员函数、全局函数格式一样
如果只是针对某个类想要重载它的new\delete时,则写为成员函数
如果想要所有类型都执行重载版本,则实现为全局函数
为什么要重载new\delete?
1、可以在重载函数中记录每次分配、释放内存的地址、代码情况、次数情况等到日志中,从而方便检查是否出现内存泄漏,以及泄漏位置
2、对于字节少、且频繁申请、释放的对象,可以在重载函数中给他多分配点内存从而减少产生碎片的可能
:: 域限定符
. 直接访问成员的运算符
?: 三目运算符
sizeof 计算字节数
typeid 获取类型信息的运算符
<< 输出运算符
>> 输入运算符
[]
()
=
—>
4、运算符重载可以自定义运算符执行过程,但是无法改变运算符的优先级
5、运算符的操作数量也不能改变
6、不能发明新的运算符
建议:
1、重载运算符要遵循一致性原则,不要随意改变运算符本身的含义
2、不要忘记实现运算符重载函数的初衷,为了提高可读性,不要随意炫技