C++中的运算符重载(非常详细)
运算符重载也称为操作符重载,在不同语境根据习惯称为运算符或操作符,含义是一样的。
在 C++ 中,对两个对象进行运算最直观的方式是使用表示相应含义的运算符,在数学式子中连接两个对象进行运算的就是运算符。例如,要表示对象 A 和对象 B 相加,最直接的方式就是写成“A+B”。
在本质上,运算符(或操作符)相当于一个函数,它有自己的参数,用来接收运算符所运算的数据;也有自己的函数名,它的函数名就是运算符;同时也有返回值,就是运算的结果值。在使用时,只需要用运算符连接两个参与运算的对象即可,比函数调用简单直观,而且代码的可读性更好。
因此,在表达一些常见的运算时,例如对两个对象的加减运算,我们往往通过重载类的相应运算符来实现。
对于内置的数据类型,C++ 已经提供了丰富的运算符供我们选择使用以完成常见的运算。例如,可以用“+”连接两个 int 类型数据或 string 类型数据,以完成数据之间的“相加”运算。下面来看一个示例程序:
然而,对于我们自定义的类,两个对象之间不能直接使用这些运算符进行运算。例如,假设我们分别定义了 Father 类和 Mother 类的两个对象,我们希望能够用加法运算符“+”连接这两个对象,从而通过运算得出一个 Baby 类的对象:
不过,幸运的是,C++ 允许我们对运算符或操作符进行重载,这样我们可以自定义运算符的行为。通过自定义运算符或操作符,我们可以让 Father 类对象与 Mother 类对象相加得到 Baby 类对象,使上述代码成为可能。
在功能上,重载运算符等同于类的成员函数,两者并无本质差别。可以简单地将重载运算符看作是一类比较特殊的成员函数。虽然成员函数可以提供与运算符相同的功能,但使用运算符可以让语句更加自然简洁,也更具可读性。例如,a.add(b)调用函数 add() 可以实现两个对象 a 和 b 相加,但表达相同含义的 a+b 语句,比 a.add(b) 更直观,也更容易理解。
在 C++ 中,定义重载运算符或操作符的语法格式如下:
在使用上,当用运算符连接两个对象进行运算时,实际上相当于调用第一个对象的运算符函数,而第二个对象则作为这个运算符函数的参数。例如,使用加法运算符对两个对象进行运算:
理解了这一点后,要想让 father+mother 得到 baby 对象,我们只需要在 Father 类中定义“+”运算符函数(因为 father 位于运算符之前,所以我们定义 father 所属的 Father 类的运算符),使其可以接受一个 Mother 类的对象作为参数,并返回一个 Baby 类的对象:
需要注意的是,这里我们只定义了 Father 类的“+”运算符,因此在用它计算时,只能将 Father 类的对象放在“+”之前,即左侧。如果希望 Mother 类的对象也放在“+”的左侧,我们需要相应地定义 Mother 类的“+”运算符函数。
在 C++ 中,对两个对象进行运算最直观的方式是使用表示相应含义的运算符,在数学式子中连接两个对象进行运算的就是运算符。例如,要表示对象 A 和对象 B 相加,最直接的方式就是写成“A+B”。
在本质上,运算符(或操作符)相当于一个函数,它有自己的参数,用来接收运算符所运算的数据;也有自己的函数名,它的函数名就是运算符;同时也有返回值,就是运算的结果值。在使用时,只需要用运算符连接两个参与运算的对象即可,比函数调用简单直观,而且代码的可读性更好。
因此,在表达一些常见的运算时,例如对两个对象的加减运算,我们往往通过重载类的相应运算符来实现。
对于内置的数据类型,C++ 已经提供了丰富的运算符供我们选择使用以完成常见的运算。例如,可以用“+”连接两个 int 类型数据或 string 类型数据,以完成数据之间的“相加”运算。下面来看一个示例程序:
int a = 3; int b = 4; // 使用加法运算符“+”计算两个 int 类型变量之和 int c = a + b; cout << a << "+" << b << " = " << c << endl; string strSub1("Hello "); string strSub2("C+++"); // 使用加法运算符“+”连接两个 string 类型变量 string strCombin = strSub1 + strSub2; cout << strSub1 << "+" << strSub2 << " = " << strCombin << endl;这种使用运算符来表达对象之间运算关系的方式,通过抽象的运算符表达了具体的运算过程,从而隐藏了运算过程的具体细节。这样既直观又自然,更符合人们的运算习惯,也便于使用。
然而,对于我们自定义的类,两个对象之间不能直接使用这些运算符进行运算。例如,假设我们分别定义了 Father 类和 Mother 类的两个对象,我们希望能够用加法运算符“+”连接这两个对象,从而通过运算得出一个 Baby 类的对象:
// 分别定义 Father 类和 Mother 类的对象 Father father; Mother mother; // 用加法运算符 "+" 连接两个对象,运算得到 Baby 类的对象 Baby baby = father + mother;上述语句看似简单,但如果没有为 Father 类定义加法运算符“+”,Father 类将不知道如何和 Mother 类的对象相加来创建 Baby 类的对象,这样的语句会导致编译错误。
不过,幸运的是,C++ 允许我们对运算符或操作符进行重载,这样我们可以自定义运算符的行为。通过自定义运算符或操作符,我们可以让 Father 类对象与 Mother 类对象相加得到 Baby 类对象,使上述代码成为可能。
在功能上,重载运算符等同于类的成员函数,两者并无本质差别。可以简单地将重载运算符看作是一类比较特殊的成员函数。虽然成员函数可以提供与运算符相同的功能,但使用运算符可以让语句更加自然简洁,也更具可读性。例如,a.add(b)调用函数 add() 可以实现两个对象 a 和 b 相加,但表达相同含义的 a+b 语句,比 a.add(b) 更直观,也更容易理解。
在 C++ 中,定义重载运算符或操作符的语法格式如下:
class 类名 { public: 返回值类型 operator 运算符 (参数列表) { // 运算符的具体运算过程 } };从这里可以看到,虽然重载运算符和类的成员函数在本质上相同,但在形式上存在一些细微的差别。普通成员函数以标识符作为函数名,而重载运算符以“operator 运算符”作为函数名。其中的 operator 表示这是一个重载的运算符函数,而其后的运算符就是我们要定义的符号。
在使用上,当用运算符连接两个对象进行运算时,实际上相当于调用第一个对象的运算符函数,而第二个对象则作为这个运算符函数的参数。例如,使用加法运算符对两个对象进行运算:
a + b;这条语句实际上等同于:
a.operator + (b);a+b 表示调用的是对象 a 的操作符 operator+ 运算符函数,而对象 b 则是这个运算符函数的参数。
理解了这一点后,要想让 father+mother 得到 baby 对象,我们只需要在 Father 类中定义“+”运算符函数(因为 father 位于运算符之前,所以我们定义 father 所属的 Father 类的运算符),使其可以接受一个 Mother 类的对象作为参数,并返回一个 Baby 类的对象:
// 母亲类 class Mother { // 省略具体定义 }; // 孩子类 class Baby { public: // 孩子类的构造函数 Baby(string strName) : m_strName(strName) { } private: // 孩子的名字 string m_strName; }; // 父亲类 class Father { public: // 重载运算符 "+",返回值为 Baby 类型,参数为 Mother 类型 Baby operator + (const Mother& mom) { // 创建一个 Baby 对象并返回,省略创建过程 return Baby("BinBin"); } };在 Father 类的重载运算符“+”中,我们可以接受一个 Mother 类的对象作为参数,并在其中创建一个 Baby 类的对象作为运算符的返回值。这样,我们就可以方便地使用“+”运算符将 Father 类的对象和 Mother 类的对象相加,从而得到一个 Baby 类的对象。
需要注意的是,这里我们只定义了 Father 类的“+”运算符,因此在用它计算时,只能将 Father 类的对象放在“+”之前,即左侧。如果希望 Mother 类的对象也放在“+”的左侧,我们需要相应地定义 Mother 类的“+”运算符函数。