首页 > 编程笔记 > C++笔记 阅读:3

C++中的运算符重载(非常详细)

运算符重载也称为操作符重载,在不同语境根据习惯称为运算符或操作符,含义是一样的。

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 类的“+”运算符函数。

相关文章