运算符重载
1.概念
C++为了增强代码的可读性,也为了让自定义类型可以实现一些基本的运算,引入了运算符重载的功能。运算符重载的本质是一些有着特殊函数名的特殊函数,也有着自己的参数列表,返回值,函数名等等,并且其返回值和参数列表和普通函数并没有太大的区别。
函数名:关键字operator + 需要重载的运算符
函数原型:返回值类型+operator+要重载的运算符(参数列表)
注意:
- 不可以在关键字之后任意加符号,创建新的运算符,比如operator@
- 函数参数必须有一个是类类型对象,至少有一个
- 有些内置类型的重载,不可以通过改造函数改变其含义,比如operator+
- 输入的形参会比真正的操作数少一个,因为有一个this指针已经隐形的输入到函数中去,并且作为第一个输入的,是左操作数。
- .* sizeof . ?: :: 以上这5个运算符不可以被调用
大部分运算符重载可以写为全局函数和类的成员函数,拿相等运算符举例
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
bool operator==(const Date& d2)
{
return _year == d2._year;
&& _month == d2._month
&& _day == d2._day;
}
private:
int _year;
int _month;
int _day;
};
这里是我们经常会用的情况,是作为一个类的成员函数来写,需要说明的是,重载函数的传参实际上是两个参数
bool operator==(Date *this,const Date& d2)
也就是说,this指针已经提前进入了函数中,充当第一个参数,这里的this就是d1的指针。另外一种情况是重载函数在类之外,也就是全局定义了这个函数,应该是下面这样写的
bool operator==(const Date d1,const Date& d2)
{
return d1._year == d2._year;
&& d1._month == d2._month
&& d1._day == d2._day;
}
这种是全局的定义形式,但是这种函数如果你直接去编译会发现出现错误,因为这三个int类型的变量都是私有的,所以我们有两种方法来解决这个问题,首先就是在类的内部定义一个返回值是私有变量的函数,然后在外部调用就可以让这个函数返回私有值。另外一种方法就是使用友元函数,进而访问私有成员变量。
赋值运算符重载
1.特征
- 赋值运算符必须是类的成员函数,不能被设定为全局函数。
Date& operate=(const Date& D1,Date& D2)//全局形式
{
D1.year=D2.year;
D1.month=D2.month;
D1.day=D2.day;
return D1;
}
当在类外设定赋值运算符重载时,编译器会直接报错,说明是不可以在类外进行赋值运算符重载。这里是因为当编译器检测到类的成员函数中没有显式定义赋值运算符的重载函数时,编译器会自动生成一个默认的重载函数。当编译器已经生成默认的重载函数之后,再执行类外的那个重载函数时,就会发生函数的冲突,进而编译器发生报错。
- 当类内没有定义时,编译器默认生成的赋值重载是直接将对象进行按字节的值拷贝。
注意:内置类型成员变量是直接进行赋值,自定义成员变量需要调用对应的类的赋值运算符重载函数进行赋值。
自定义类型的默认赋值运算符也是进行值拷贝。
那么当我们对日期类对象进行运算符重载时,运算符重载函数其实就可以直接进行省略,但是当类内部有新的空间开辟时,我们就不能直接进行值拷贝了,否则开辟的空间面临被释放两次的风险。
前置++和后置++的重载
++的重载是基于+=来进行定义的,两种加加的区别在一个是先使用值再进行加1,另一个是先进行加1,再使用值。
我们还是以日期类为例
class Date
{
public:
Date& operate++()//前置++
{
_day++;
return *this;
}
Date operate++(int)//后置++
{
Date tmp(*this);//使用拷贝构造函数
_day++;
return tmp;
}
private:
int _year;
int _month;
int _day;
}
在以上的代码中,我们有一些注意事项需要说明。
1.特征
- 因为前置++和后置++都是一元操作符,并且为了让两个操作符可以正确重载,所以前置++和后置++的成员函数名有所不同,前置++的括号中不用传参,而后置++需要进行传一个int类型的值,在实际使用中这个值可以是任意一个int值。
- 前置的返回值是一个引用,而后置的返回是一个类的值,因为前者是直接在原本的类上进行加一,然后返回原来的那个值,所以可以直接返回引用,还省去了一个复制的步骤,加快效率。
后者返回的是一个临时创建的类,在重载函数结束之后,这个临时变量会直接销毁,所以只能进行值的复制,然后传出来。