C++提供了操作符的重载,是操作符有了多种语义。它使用了operator关键字,后接需要定义的操作符符号。
可以使用的函数有全局重载函数和类成员函数,当使用全局函数重载操作符时必须在类能声明这个函数是友元函数,才能访问类里私有成员变量,这是两种函数的区别之一。区别之二就是使用类成员函数重载操作符时,参数只需要是操作符的右值即可,因为类内有this指针,指向的对象可以作为左值。
这里先实现 输入输出;赋值运算;相等不等;加、减、乘、除;等操作符的重载。
#include <iostream>
using namespace std;
class Test
{
private:
int x;
int y;
public:
Test(int _x = 0, int _y = 0): x(_x), y(_y){}
int getx() { return x; }
int gety() { return y; }
Test operator+ (const Test &T2); // '+'
Test operator- (const Test &T2); // '-'
Test operator* (const Test &T2); // '*'
Test operator/ (const Test &T2); // '/'
friend ostream& operator<< (ostream& os, const Test &obj); // '<<'
friend istream& operator>> (istream& in, Test &obj); // '>>'
bool operator== (const Test &T2); // '=='
bool operator!= (const Test &T2); // '!='
Test& operator= (const Test &T2); // '='
Test& operator++ (); // ++Test
Test operator++ (int); // Test++
~Test() {}
};
Test Test::operator+ (const Test &T2)
{
Test ret;
ret.x = x + T2.x;
ret.y = y + T2.y;
return ret;
}
Test Test::operator- (const Test &T2)
{
Test ret;
ret.x = x - T2.x;
ret.y = y - T2.y;
return ret;
}
ostream& operator<< (ostream& os, const Test &obj)
{
os<<obj.x << " "<<obj.y;
return os;
}
istream& operator>> (istream& in, Test &obj)
{
in>>obj.x>>obj.y;
return in;
}
bool Test::operator== (const Test &T2)
{
return (x == T2.x) && (y == T2.y);
}
bool Test::operator!= (const Test &T2)
{
return !(*this == T2);
}
Test& Test::operator= (const Test &T2)
{
x = T2.x;
y = T2.y;
return *this;
}
Test& Test::operator++ ()
{
++x;
++y;
return *this;
}
Test Test::operator++ (int)
{
Test ret = *this;
x++;
y++;
return ret;
}
注意的几点:
1、输入和输出操作符的重载函数的返回类型必须是引用,赋值操作符的重载函数返回类型,这是为了满足它们的链式使用,如 cin>>a>>b; a = b = c; 引用可以作为左值来使用。
2、在赋值操作符重载时,如果类内有指针成员变量,要小心使用,下面会讲到。
3、在自增和自减时有前后之分,这里用到了占位符,函数没有参数时表示是前自增,有占位符参数时表示后自增,而且前自增返回的是引用。
对于含有指针成员变量的类,在重载赋值操作符时要注意指针指向空间的改变,拷贝构造函数也要实现正确的初始化;这是是对'=' '[]' 操作符的重载:
class Test
{
private:
int mLength;
int *mSpace;
public:
Test(int length = 0):mLength(length)
{
mSpace = new int[mLength];
}
Test(const Test& obj);
int& operator[] (int i);
Test& operator= (const Test &T2);
void get();
void put();
~Test()
{
mLength = -1;
delete[] mSpace;
}
};
Test::Test(const Test& obj)
{
delete[] mSpace;
mLength = obj.mLength;
mSpace = new int[obj.mLength];
for(int i=0; i<mLength; i++)
{
mSpace[i] = obj.mSpace[i];
}
}
void Test::get()
{
for(int i=0; i < mLength; i++)
{
mSpace[i] = i+1;
}
}
void Test::put()
{
for(int i=0; i< mLength; i++)
{
cout<<mSpace[i]<<endl;
}
}
int& Test::operator[] (int i)
{
return mSpace[i];
}
Test& Test::operator= (const Test &T2)
{
delete[] mSpace;
mLength = T2.mLength;
mSpace = new int[mLength];
for(int i=0; i<mLength; i++)
{
mSpace[i] = T2.mSpace[i];
}
return *this;
}
注意:在赋值操作符的重载时,必须先将 左值对象的指针成员变量销毁,然后按照右值对象的指针指向的空间大小分配合适的内存空间,而在拷贝构造函数时则不能提前释放左值对象的指针成员变量所指向的内存空间,因为这时在拷贝构造函数被执行时,左值对象的指针成员变量根本还没有被初始化,也就不存在已经分配了的内存空间,这是拷贝构造函数和赋值操作符的区别。
Test t1(10);
Test t2 = t1; //这里调用的是拷贝构造函数,t2根本就没有执行普通的构造函数。
Test t1(10);
Test t2(5);
t2 = t1; //这里t2之前已经调用了普通构造函数,因此它的指针成员变量已经分配过内存空间了,这里必须释放掉后才能重新分配新的内存空间,以免内存泄露。
后续:重载‘=’操作符时忽略了一个很重要的检查即:自赋值检查,自己赋值给自己。这样如果直接delete操作将再也找不回所指内存的数据。因此应该改成:
Test& Test::operator= (const Test &T2)
{
/*检查自赋值*/
if(this == &T2)
return *this;
......
......
}
关于拷贝构造函数和赋值操作符重载的深入介绍http://blog.csdn.net/dwb1015/article/details/27707043