一、操作符函数
- 什么是操作符函数:在C++中针对类 类型的对象的运算符,由于他们肯定不支持真正的运算符,编译器会将他们翻译成函数进行,这种就叫操作符函数(运算符函数)
- 通过编译器把运算符编译成运算符函数,可以针对自定义的类类型设计它独有的运算功能
- 其实各种运算符已经具备一些功能,再次定义就类似于运算符重载
双目运算符工作机制:
A+B
成员函数
A.operator+(B)
全局函数
operator+(A,B)
单目运算符
二、双目操作符函数重载
成员函数:
const 类对象 operator#(const 类& that) const
{
return 类(参数#参数)
}
注意:双目运算符的结果是一个右值,返回值应该家一个 const
为了const对象能够调用参数应该写一个const,函数也应该具备const属性
自变运算符要改变自身的值,所以不用加
全局函数:
const 类 operator#(const 类&a,const 类&b)
{
}
注意:全局函数不是成员函数,可能会访问类的私有成员,可以把函数声明为类的友元函数
友元函数:在类的外部某个函数中想访问类的私有成员时,需要所在的函数声明为友元,但是友元只是朋友,因此它只有访问权,没有实际的拥有权,其根本原因是没有类的this指针
private/protected/public 都可以访问
友元函数的声明,函数的声明写一份到类中,声明前加上friend关键字,使用友元既可以把操作符函数定义为全局的,也可以确保类的封装性
注意:友元函数与成员函数不会构成重载关系,因为他们作用域不同,
三、赋值类型的双目操作符
- 获取单参构造赋值运算符的调用方式
String str=“sunll”;会调用单参构造,而不调用赋值运算符 - 左操作数据不能具有const属性
1、成员函数不能是常函数
2、全局函数第一个参数不能具有const属性
3、(成员/全局)应该都具备const属性的返回值
四、单目操作符函数重载
成员
类& operator #(void)
{
}
类& operator #(const 类& that)
五、输入输出操作符重载
cout是ostream类型的对象
cout是istream类型的对象
如果<</>>运算实现为成员函数,那么调用者应该是ostream/istream
而我们无权增加标准库的代码,因此输入输出运算符只能定义成全局函数
ostream& operator <<(ostream & os,const 类& n)
{
}
注意:在输入输出过程中,cin和cout会记录错误标志,因此不能加const属性
六、特殊操作符
- 下标操作符 [],常用于容器类型中以下标方式获取容器元素
类型& operator[](int i)
{
} - 函数操作符(),一个类如果重载了函数操作符,那么他的对象就可以像函数一样
使用,参数的个数、返回值、类可以不确定,它是唯一一个可以参数有缺省参数的操作符 - 解引用操作符 ,成员访问操作符->
如果一个类重载了和->,那么它的对象就可以像指针一样使用
所谓的智能指针就是一种类对象,它支持解引用和成员访问操作符 - 智能指针
常规指针的缺点:
当常规指针离开他的作用域时,只有该指针所占用的空间会被释放,而他
所指向的内存空间能否被释放就不一定了,在一些特殊情况下(人为、业务逻辑特殊)free
delete没有执行,就会形成内存泄露
智能指针的优点:
智能指针是封装了常规指针的类对象,当它离开在作用域时,它的析构函数会自动执行
他的析构函数会负责释放常规指针所指向的动态内存(以正确方式构建的智能指针,它的析构函数才会正确执行)
智能指针和常规指针的相同点
都支持*和->运算
智能指针和常规指针的不同点
任何时候,一个对象只能使用一个智能指针来指向,而常规指针可以指向多次
智能指针的赋值操作需要经过拷贝构造、赋值构造特殊处理(深拷贝)
auto_ptr:标准库中封装好的智能指针,实现了常规指针的基本功能,
头文件#include
用法:auto_ptr<指向的类型>智能指针变量名(对象的地址)
auto_ptr的局限性:
不能跨作用域使用,一旦离开作用域指针变量会释放它指向的对象也会释放
不能放入标准容器
不能指向对象数组
- new/delete/new[]/delete[]运算符重载
1、C++中缺省的堆内存管理器速度较慢,重载 new/delete 底层使用 malloc/free
可以提高运行速度。
2、new 在失败时会产生异常,而每次使用都应该进行异常捕获,重载new运算符,只需要
在操作符函数中进行一次错误处理即可
3、在一些占字节数比较小的类,频繁使用 new 可能会产生大量的的内存碎片,而重载new
操作符后,可以适当的扩大每次申请的字节数,减少内存碎片的产生几率
4、重载 new/delete 记录堆内存使用的信息
5、重载 delete 可以检查到释放内存失败的信息,检查到内存泄露
七、重载操作符的限制
- 不能进行重载的操作符
域限定符::
直接成员访问操作符.
条件运算符?:;
字节长度操作符 sizeof
类型信息操作符 typeid
强制类型转换操作符 const_cast,dynamic,reinterpret_cast,static_cast - 重载操作符不能修改操作符的优先级
- 无法重载所有基本类型的操作符运算
- 不能修改操作符的参数个数
- 不能发明新的操作符
- 大多数运算符都可以通过成员或者非成员函数进行重载,但是以下运算符只能通过成员函数重载
1、赋值运算符 =
2、函数调用运算符()
3、下标运算符[]
4、通过指针访问类成员的运算符->
关于运算符重载的建议:
8. 在实现重载操作符的时候要根据操作符实际的功能和意义来确定具体参数返回值,是否具有const属性,返回值是否是引用或者临时对象。
9. 重载操作符要符合情理(要有意义),以实际用途为前提,
10. 重载操作符是为了让对象的操作更加简单方便,提高代码可读性
11. 重载操作符要追求一致性,要与默认操作符运算规则一致