在编程过程中,有时希望使对象也能够通过运算符进行运算,可以使得代码更加容易理解,比如说数学上复数的+、-运算,但C++中,无法对两个复数对象直接应用+或-运算符。
我们希望能够写出 Complex_a + Complex_b 这样的语句。
定义
运算符重载,就是对已有的(C++中预定义好的)运算符赋予多重的含义,使对同一运算符作用于不同类型的数据时导致不同类型的行为。
也就是说,对于同一个运算符,针对不同类型的操作数,所发生的的行为也就不同。
运算符的重载,其实质上是函数重载。
在使用过程中,能够将含运算符的表达式转换成对运算符函数的调用,在此同时,将运算符的操作数转换成运算符函数的参数。
其形式,如下所示:
返回值类型 operator 运算符(形参表)
{
……
}
目的
拓展C++ 中提供的运算符的适用范围,使之能够作用于对象。
性质说明
关于运算符的重载,其实质上是函数的重载,可以重载为普通的函数,也可以重载为类的成员函数。
当重载为普通函数时,函数的参数个数是运算符目数; 当重载为成员函数时,函数的参数个数是运算符目数减一。
至于这样性质的产生原因,我们在以下的实例中做出解释:
class Complex
{
public:
double real, imag;
Complex (double r=0.0, double i=0.0):real(r),imag(i) { }
Complex operate - (const Complex &c);
};
Complex operate + (const Complex &a, const Complex &b)
{
return Complex(a.real+ b.real, a.imag+ b.imag);
}
Complex Complex::operate - (const Complex & c)
{
return Complex(real- c.real, imag- c.imag);
}
int main()
{
Complex a(4,4), b(1,1), c;
c = a+ b
std::cout<< c.real<< ","<< c.imag<< std::endl;
std::cout<< (a-b).real<< ","<< (a-b).imag<< endl;
return 0;
}
至于为什么作为普通函数的运算符重载的参数为运算符目数,作为成员函数的运算符重载参数为运算符目数减一: (1)c = a+ b语句等价于c = operator+(a,b),a+b 的地位是函数返回的一个临时变量,用后及删。无需对a+b中任何元素作保存的必要
(2)而(a- b).real 语句等价于a.operator-(b).real,后续读取real的操作,(或者说为了方便后续使用类内其他函数),就要求了a-b的返回值必须继续存储在a中,故而传入的参数仅为b一个(即运算符目数减一),而a作为operator-()调用的对象存在,在调用后存储a-b的结果。
赋值运算符的重载
在有些时候,我们希望赋值运算符量变的类型可以不是匹配的,比如将一个char * 类型的字符串赋值给一个字符串对象,这时就需要重载赋值运算符“=”了。
注: 赋值运算符“=” 只能重载为成员函数。
class String{
private:
char * str;
public:
String ():str(new char[1]){ str[0]= 0;}
const char * c_str() { return str;};
String & operator = (const char * s);
~String() { delete [] str;}
};
String & String::operator=(const char * s)
{
delete [] str;
str = new char[strlen(s)+1];
strcpy( str,s);
return * this;
}
int main()
{
String s;
s = "Good Luck,";
cout<< s.c_str() <<endl;
s = "Shenzhou 8!";
cout << s.c_str() << endl;
return 0;
}
------------------------华丽分割线--------------------------------- 对于赋值运算符的重载,上述例子中是class = char类型的重载,如果是应用于以下情况呢?
String s;
s = "Hello";
s = s;
我们仿之前实例中的一段代码进行修改,这时候就出现了一些问题。 以下是原代码: 修改过后:
String & String::operator=(const String & s)
{
delete [] str;
str = new char[strlen(s.str)+1];
strcpy( str,s.str);
return * this;
发现并不能满足上述s=s 的使用需求:重载函数会将 s.str 删掉,这样就没有办法再为等号左边的s进行赋值了。于是再做修改:
String & String::operator=(const String & s)
{
if (this == &s)
return *this;
delete [] str;
str = new char[strlen(s.str)+1];
strcpy( str,s.str);
return * this;
-----------------------------再度分割----------------------------------- 这样就莫得问题了嘛,大抵还是有的。
由于“=”比较特殊,在为String类编写复制构造函数时,会产生一个问题,我们先将修改结果进行展示:
String (String & s)
{
str == new char[strlen(s.str)+1];
strcpy(str , s.str);
}
下面展示默认构造函数的问题,先来看operate = 的返回值类型,我们发现实例中的返回值均为String &,那么为什么不用void或者String呢???
事实上,在C++预定义的“=”中,其返回值是为等号左边变量的引用。例如整型a=3,b=5,在a=b后返回的值为a的新值5 对于a=b=c;和(a=b)=c; 分别等价于a.operator = (b.operator = ( c )); (a.operator=(b)).operator=( c ); “=”的运算结果为等号左边的变量的引用 对运算符进行重载的时候,好的风格是应该尽量保留运算符原本的特性
|