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