运算符重载
C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
class Date
{
public:
int getyear() const
{
return _year;
}
int getmonth() const
{
return _month;
}
int getday() const
{
return _day;
}
private:
int _year = 1970;
int _month = 1;
int _day = 1;
};
void operator<<(ostream& out, const Date& d)
{
out << d.getyear() << "年" << d.getmonth() << "月" << d.getday() << "日" << endl;
}
int main()
{
int arr = 10;
cout << arr << endl;
Date d;
cout << d;
return 0;
}
如上述中, 可以让自定义类型与内置类型一样进行运算符操作,赋予新的意思
函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)
注意:
- 不能通过连接其他符号来创建新的操作符:比如operator@
- 重载操作符必须有一个类类型参数
- 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义
- 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
- .* :: sizeof ?: . 注意以上5个运算符不能重载。
赋值运算符重载
- 赋值运算符重载格式
- 参数类型:const T&,传递引用可以提高传参效率
- 返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
class Date
{
public :
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
Date (const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
Date& operator=(const Date& d)
{
if(this != &d) //防止自己给自己赋值
{
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this; //为了复合连续赋值
}
private:
int _year ;
int _month ;
int _day ;
};
- 赋值运算符只能重载成类的成员函数
当赋值运算符重载成全局函数,这时重载成全局函数时没有this指针了,需要给两个参数
class Date
{
public:
Date(int year = 1970, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
int _year;
int _month;
int _day;
};
// 注意这时重载成全局函数时没有this指针了,需要给两个参数
Date& operator=(Date& l, const Date& r)
{
if (&l != &r)
{
l._year = r._year;
l._month = r._month;
l._day = r._day;
}
return l;
}
这样的编译器会报错
原因: 赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值万事达运算符重载只能是类的成员函数
用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
Date d2 = d1;
return 0;
}
既然编译器生成的默认赋值运算符重载函数已经可以完成字节序的值拷贝了,还需要自己实现吗?当然像日期类这样的类是没必要的,但是面对的像栈,队列这种的需要涉及到资源管理,必须要自己实现。
因为编译器的自己生成的赋值运算符重载函数只能以字节的方式一个一个拷贝,这样的后果会出现,任意一个栈的操作都会互相影响,同时析构函数的存在,对同一块空间同时释放两次
前置++和后置++重载函数
前置++和后置++都是一元运算符,为了让前置++与后置++形成能正确重载
后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器
自动传递
// 前置++:返回+1之后的结果
// 注意:this指向的对象函数结束后不会销毁,故以引用方式返回提高效率
Date& operator++() // 前置++
{
_day += 1;
return *this;
}
Date operator++(int) //后置++
{
Date temp(*this);
_day += 1;
return temp;
}