### 运算符重载

我们在定义两个整型变量时，可以实现两个整型变量的加法运算，如果定义两个同类型的类对象，能否进行加法运算的？默认时当然是不允许的，因为编译器没有提供该功能。例如：

CUser User, comUser;

CUser defUser = User + comUser; //错误的语句，无法通过编译

如果我们在 CUser 类中重载“+”运算符，则可以实现两个同类型对象的加法运算。例如：

运算符重载

class CUser //定义一个类

{

public: //设置成员访问级别

char m_Username[128]; //定义数据成员

char m_Password[128]; //定义数据成员

int m_nLevel; //操作员级别

public:

CUser() //默认构造函数

{

m_nLevel = 1;

strcpy(m_Username, "MR"); //为数据成员赋值

strcpy(m_Password, "KJ"); //为数据成员赋值

cout << "构造函数被调用!" << endl; //输出信息

}

CUser operator + (CUser & refUser) //重载+运算符

{

CUser User;

User.m_nLevel = m_nLevel + refUser.m_nLevel;

return User;

}

};

上述代码中，为 CUser 类实现了+运算符的重载。运算符重载需要使用 operator 关键字，其后是需要重载的运算符，参数及返回值根据实际需要来设置。下面在 main 函数中定义 3 个 CUser 对象，将两个对象进行加法运算，赋值给第 3 个对象。

int main(int argc, char* argv[])

{

CUser User, comUser;

CUser defUser = User + comUser; //进行加法运算

cout << "m_nLevel = " << defUser.m_nLevel << endl;

return 0;

}

运行程序，效果如图 1 所示。

图 1 重载+运算符

如果用户想要实现 CUser 对象与一个整数相加，可以通过修改重载运算符的参数来实现。例如：

CUser operator + (int nData) //实现 CUser 对象与整数加法运算

{

CUser User;

User.m_nLevel = m_nLevel + nData;

return User;

}

这样就可以实现 CUser 对象与一个整数的加法运算了。例如：

CUser User;

CUser defUser = User + 10; //CUser 对象与整数进行加法运算

实际上，CUser operator + (int nData)与 CUser operator + (CUser & refUser)函数是可以同时存在的，即表示重载函数。这样在 CUser 类中即可以实现两个 CUser 类对象的加法运算，也可以实现 CUser 对象与整数的加法运算。

我们知道整数的加法运算符合交换律，即 A + B 等于 B + A。但是对于重载的+运算符来说，“User + 10” 不能够写为“10 + User”。为了使语句“CUser defUser = 10 + User;”能够通过编译，可以定义一个全局的运算符重载函数。例如：

CUser operator+ (int nData, CUser &refUser) //全局运算符重载函数

{

CUser User;

User.m_nLevel = refUser.m_nLevel + nData;

return User;

}

这样，语句“CUser defUser = 10 + User;”就成为了合法的语句。在上述函数中，注意参数的顺序，整型要放置在前面，CUser 类型放置在后面，不能够进行倒置，否则语句仍然不能通过编译。

对于++和--运算符，由于涉及到前置运算和后置运算，在重载这类运算符时如何区分前置运算还是后置运算呢？默认情况下，如果重载运算符没有参数，则表示是前置运算。例如：

void operator++() //前置运算

{

++m_nLevel;

}

如果重载运算符使用了整数作为参数，则表示是后置运算，此时的参数值可以被忽略，它只是一个标识，标识后置运算。

void operator++(int) //后置运算

{

++m_nLevel;

}

运算符重载具有强大的功能，我们可以通过重载=运算符将一个整数赋值给一个对象。那么如何实现将一个对象赋值给一个整数呢？有人马上想到使用全局运算符重载函数。但不幸的是对于重载“=”、“[]”和“->”运算符来说，只能是类的成员函数，而不能是全局函数。要实现将对象赋值给整数，可以使用 C++提供的转换运算符。例如：

转换运算符

class CUser //定义一个类

{

public: //设置成员访问级别

char m_Username[128]; //定义数据成员

char m_Password[128]; //定义数据成员

int m_nLevel; //操作员级别

public:

CUser() //默认构造函数

{

m_nLevel = 1;

strcpy(m_Username, "MR"); //为数据成员赋值

strcpy(m_Password, "KJ"); //为数据成员赋值

cout << "构造函数被调用!" << endl; //输出信息

}

operator int () //转换运算符

{

return m_nLevel;

}

};

上述代码在定义 CUser 类时定义了一个转换运算符 int，用于实现将 CBook 类赋值给整型变量。转换运算符由关键字 operator 开始，其后是转换为的数据类型。在定义转换运算符时，注意 operator 关键字前没有数据类型，虽然转换运算符实际返回了一个转换后的值，但是不能够指定返回值的数据类型。

下面在 main 函数中定义一个 CUser 对象，将该对象赋值给一个整型变量。

int main(int argc, char* argv[])

{

CUser User;

int nData = User; //将 CUser 对象赋值给一个整型变量

cout << "m_nLevel = " << nData << endl;

return 0;

}

用户在程序中重载运算符时，需要遵守如下规则和注意事项。

q 并不是所有的 C++运算符都可以重载

对于 C++中的大多数运算符来说都可以进行重载。但是，“::”、“?”、“:”和“.”运算符不能够被重载。

q 运算符重载的一些限制

（1）我们不能构建新的运算符。

（2）不能改变原有运算符操作数的个数。

（3）不能改变原有运算符的优先级。

（4）不能改变原有运算符的结合性。

（5）不能改变原有运算符的语法结构。

q 运算符重载的基本准则

（1）一元操作数可以是不带参数的成员函数，或者是带一个参数的非成员函数。

（2）二元操作数可以是带一个参数的成员函数，或者是带 2 个参数的非成员函数。

（3）“=”、“[]”、“->”和“（）”运算符只能定义为成员函数。

（4）“->”运算符的返回值必须是指针类型或者能够使用“->”运算符类型的对象。

（5）重载“++”和“--”运算符时，带一个 int 类型参数，表示后置运算，不带参数表示前置运算。