operator是C++的关键字,它和运算符一起使用,表示一个运算符函数,理解时应将operator=整体上视为一个函数名。
这是C++扩展运算符功能的方法,虽然样子古怪,但也可以理解:一方面要使运算符的使用方法与其原来一致,另
一方面扩展其功能只能通过函数的方式(c++中,“功能”都是由函数实现的)。
一、为什么使用操作符重载?
对于系统的所有操作符,一般情况下,只支持基本数据类型和标准库中提供的class,对于用户自己定义class,
如果想支持基本操作,比如比较大小,判断是否相等,等等,则需要用户自己来定义关于这个操作符的具体实现。比
如,判断两个人是否一样大,我们默认的规则是按照其年龄来比较,所以,在设计person 这个class的时候,我们需要
考虑操作符==,而且,根据刚才的分析,比较的依据应该是age。那么为什么叫重载呢?这是因为,在编译器实现的时
候,已经为我们提供了这个操作符的基本数据类型实现版本,但是现在他的操作数变成了用户定义的数据类型class,
所以,需要用户自己来提供该参数版本的实现。
二、如何声明一个重载的操作符?
A: 操作符重载实现为类成员函数
重载的操作符在类体中被声明,声明方式如同普通成员函数一样,只不过他的名字包含关键字operator,以及紧跟其
后的一个C++预定义的操作符。
可以用如下的方式来声明一个预定义的==操作符:
-
class person{
-
private:
-
int age;
-
public:
-
person( int a)
-
{
-
this->age=a;
-
}
-
inline bool operator == ( const person &ps) const;
-
};
实现方式如下:
-
inline bool person::operator==( const person &ps) const
-
{
-
-
if ( this->age==ps.age)
-
return true;
-
return false;
-
}
调用方式如下:
-
-
using namespace std;
-
int main()
-
{
-
person p1( 10);
-
person p2( 20);
-
if(p1==p2)
-
cout<<”the age is equal!”< return 0;
-
}
这里,因为operator ==是class person的一个成员函数,所以对象p1,p2都可以调用该函数,上面的if语句中,相当
于p1调用函数==,把p2作为该函数的一个参数传递给该函数,从而实现了两个对象的比较。
B:操作符重载实现为非类成员函数(全局函数)
对于全局重载操作符,代表左操作数的参数必须被显式指定。例如:
-
</pre><pre name= "code" class= "objc">
-
using namespace std;
-
class person
-
{
-
public:
-
int age;
-
public:
-
person( int _age = 0)
-
:age(_age)
-
{
-
cout << "person(int _age )"<< endl;
-
}
-
-
person(person& ps)
-
{
-
* this = ps;
-
}
-
};
-
bool operator==(person& p1, person const & p2) //全局重载操作符==
-
{
-
if (p1.age == p2.age)
-
{
-
return true; //满足要求
-
}
-
return false;
-
}
-
int main()
-
{
-
person rose;
-
person jack;
-
rose.age = 18;
-
jack.age = 23;
-
if (rose == jack)
-
{
-
cout << " is equal " << endl;
-
}
-
cout << "not equal " << endl;
-
return 0;
-
}
C:如何决定把一个操作符重载为类成员函数还是全局名字空间的成员呢?
①如果一个重载操作符是类成员,那么只有当与 它的左操数是该类的对象时,该操作符才会被调用。如果
该操作符的左操作数必须是其他的类型,则操作符必须被重载为全局名字空间的成员。
②C++要求赋值=,下标[],调用(), 和成员指向-> 操作符必须被定义为类成员操作符。任何把这些操作符定义为名
字空间成员的定义都会被标记为编译时刻错误。
③如果有一个操作数是类类型如string类的情形那么对于对称操作符比如等于操作符最好定义为全局名字空间成员。
D:操作符重载适用范围:
E:重载运算符的限制:
1、只有C++预定义的操作符才可以被重载;
2、对于内置类型的操作符,它的预定义不能改变,即不能改变操作符原来的功能;
3、重载操作符不能改变他们的操作符优先级;
4、重载操作符不能改变操作数的个数;
5、除了对()操作符外,对其他重载操作符提供缺省实参都是非法的;
F:注意
1、当返回值不是本函数内定义的局部变量时就可以返回一个引用。在通常情况下,引用返回值只用在需对函
数的调用重新赋值的场合,也就是对函数的返回值重新赋值的时候。(以重载赋值= 为例!)
如果返回值:返回的局部对象,在赋值语句结束之后释放,函数返回时保存的临时变量为该对象;
如果返回引用:返回的局部对象,在函数返回时释放,函数返回时保存的临时变量为该对象的引用(地址);
2、在增量运算符中,放上一个整数形参,就是后增量运行符,它是值返回,对于前增量没有形参,而且是引用返回。
例如:
-
class Test
-
{
-
public:
-
Test( int x = 3)
-
{
-
m_value = x;
-
}
-
Test& operator++(); //前增量
-
Test operator++( int); //后增量
-
private:
-
int m_value;
-
};
-
Test& Test::operator++()
-
{
-
m_value++; //先增量
-
return * this; //返回当前对象
-
}
-
Test Test::operator++( int)
-
{
-
Test temp(* this); //创建临时对象
-
m_value++; //再增量
-
return temp; //返回临时对象
-
}
在函数的运行前执行还是运行后执行
y=i++;//先执行y=i,再执行i=i+1
y=++i;//先执行i=i+1,再执行y=i
使用前增量时,对对象(操作数)进行增量修改,然后再返回该对象.所以前增量运算符操作时,参数与返回的是同一个对象.着与基本数据类型的前增量操作相似,返回的也是左值.
使用后增量时,必须在增量之前返回原有的对象值.为此,需要创建一个临时对象,存放原有的对象,以便对操作数(对象)进行增量修改时,保存最初的值.后增量操作返回的是原有对象的值,不是原有对象,原有对象已被增量修改,所以返回的应该是存放原有对象值的临时对象.
在增量运算符定义中,放上一个整数形参,就是后增量运算符.