运算符重载
C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类 型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。运算符重载可以让编译器按照指定的规则对自定义类型对象直接进行一些运算符操作。
函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)
class Date
{
public:
Date(int year = 2020,int month = 1,int day = 1)//默认构造函数
:_year(year)
,_month(month)
,_day(day)
{
}
bool operator>(const Date& d)
{
return _year > d._year ||
_year == d._year&& _month > d._month ||
_year == d._year&&_month == d._month&&_day>d._day;
}
bool operator==(const Date& d)
{
return _year ==d._year&&_month==d._month&&_day==d._day;
}
bool operator!=(const Date& d)
{
return !(*this==d);
}
private:
int _year;
int _month;
int _day;
};
运算符重载的特性
1 不能通过连接其他符号来创建新的操作符:比如operator@ 重载操作符必须有一个类类型或者枚举类型的操作数
2 用于内置类型的操作符,其含义不能改变,例如:内置的整型+,
3 不能改变其含义 作为类成员的重载函数时,其形参看起来比操作数数目少1成员函数的 操作符有一个默认的形参this,限定为第一个形参
4 .* 、:: 、sizeof 、?: 、. 注意以上5个运算符不能重载。。
赋值运算符重载
赋值运算符中重要的一点: 一个类如果没有显式定义赋值运算符重载,编译器也会生成一个,完成对象按字节序的浅拷贝。
浅拷贝在不涉及资源管理的类中不存在问题,但是若是类中涉及资源管理就会造成两个对象公用一块内存空间,在对象的生命周期结束时,同一份资源多次释放而导致的代码崩溃
class Date
{
public:
Date(int year = 2020,int month = 1,int day = 1)//默认构造函数
:_year(year)
,_month(month)
,_day(day)
{
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2020,2,2);
Date d2;
d1 = d2;
return 0;
}
在Date类中不涉及资源管理所以可以不用显式的给出赋值运算符重载函数,编译器会自动生成一个,这里d1调用的编译器生成operator=完成拷贝,d2和d1的值也是一样的,但是在涉及资源管理的就不可以
class String{
public:
String(const char* str = "")
{
_str = (char*)malloc(strlen(str) + 1);
strcpy(_str, str);
}
~String()
{
cout << "~String()" << endl;
free(_str);
}
private:
char* _str;
};
int main()
{
String s1("hello");
String s2("world");
s1 = s2;
}
在这种涉及资源管理但是没有显式的给出赋值运算符重载,编译器就会自动生成默认的赋值运算符重载函数,就会发生浅拷贝,后果就是代码崩溃
以Date类为例给出它的赋值运算符重载函数
Date& operator=(const Date& d)//赋值运算符重载
//参数 :选择使用引用传参 : 传参的效率高
{
if(*this!=d)//判断是否给自己赋值
{
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this;
//返回值, 一定要有返回值,否则不能连续赋值
//a=b=c;----> c--->b b---->a
}
注意:
参数:传引用,效率高
返回值:返回*this,否则不能连续赋值
检测是否自己给自己赋值