C++ 运算符重载

C++ 运算符重载让一个运算符具有多种工作方式,本文结合示例介绍了运算符重载。

在 C++ 中,我们可以改变运算符对用户定义类型(如对象和结构体)的工作方式。这称为运算符重载。例如,

假设我们创建了一个名为 Complex 表示复数的类,并创建了三个对象 c1, c2result

由于运算符重载允许我们改变运算符的工作方式,我们可以重新定义 + 运算符的工作方式并使用它来完成 c1 + c2。 如下:

result = c1 + c2;

而不是像

result = c1.addNumbers(c2);

这使我们的代码直观且易于理解。

**注:**我们不能将运算符重载用于基本数据类型,例如 intfloatchar 等等。

C++ 运算符重载的语法

为了重载一个运算符,我们使用了一个特殊的 operator 函数。我们在类或结构体中定义此函数,我们希望重载运算符能够用于该类或结构体的对象或者变量。

class className {
    ... .. ...
    public
       returnType operator symbol (arguments) {
           ... .. ...
       }
    ... .. ...
};

这里,

  • returnType 是函数的返回类型。
  • operator 是关键字。
  • symbol 是我们要重载的运算符。比如: +<-++ 等。
  • arguments 是传递给函数的参数。

一元运算符中的运算符重载

一元运算符仅对一个操作数进行操作。递增运算符 ++ 和递减运算符 -- 是很常见的一元运算符。

示例 1:++ 运算符(一元运算符)重载

本示例演示了在 C++ 中重载作为前缀的递增运算符 ++

#include <iostream>
using namespace std;

class Count {
   private:
    int value;

   public:

    // Constructor to initialize count to 5
    Count() : value(5) {}

    // Overload ++ when used as prefix
    void operator ++ () {
        ++value;
    }

    void display() {
        cout << "Count: " << value << endl;
    }
};

int main() {
    Count count1;

    // Call the "void operator ++ ()" function
    ++count1;

    count1.display();
    return 0;
}

输出

Count: 6

在这里,当我们使用 ++count1; 时, void operator ++ () 被调用。这将 Count 对象 count1value 属性加 1。

**注意:**当我们重载运算符时,我们可以使用它以我们喜欢的任何方式工作。例如,我们可以用来 ++value 加 100。

然而,这使我们的代码混乱且难以理解。作为程序员,我们的工作是以一致和直观的方式正确使用运算符重载。

上面的示例仅在 ++ 用作前缀时才有效。为了让 ++ 作为后缀,我们使用这种语法。

void operator ++ (int) {
    // code
}

注意括号内的内容 int。这是用于使用一元运算符作为后缀的语法;它不是函数参数。

示例 2:++ 运算符(一元运算符)重载

本示例演示了在 C++ 中重载作为前缀和后缀的递增运算符 ++

#include <iostream>
using namespace std;

class Count {
   private:
    int value;

   public:

    // Constructor to initialize count to 5
    Count() : value(5) {}

    // Overload ++ when used as prefix
    void operator ++ () {
        ++value;
    }

    // Overload ++ when used as postfix
    void operator ++ (int) {
        value++;
    }

    void display() {
        cout << "Count: " << value << endl;
    }
};

int main() {
    Count count1;

    // Call the "void operator ++ (int)" function
    count1++;
    count1.display();

    // Call the "void operator ++ ()" function
    ++count1;

    count1.display();
    return 0;
}

输出

Count: 6
Count: 7

在示例 2 中 ++ 被用作前缀和后缀。但是,如果我们尝试做这样的事情,它就行不通:

Count count1, result;

// Error
result = ++count1;

这是因为我们的操作符函数的返回类型是 void . 我们可以通过使 Count 作为操作符函数的返回类型来解决这个问题。

// 使用 ++ 作为前缀时返回 Count
Count operator ++ () {
    // code
}


// 使用 ++ 作为后缀时返回 Count
Count operator ++ (int) {
   // code
}

示例 3:运算符函数的返回值(++ 运算符)

#include <iostream>
using namespace std;

class Count {
   private:
    int value;

   public
       :
    // Constructor to initialize count to 5
    Count() : value(5) {}

    // Overload ++ when used as prefix
    Count operator ++ () {
        Count temp;

        // Here, value is the value attribute of the calling object
        temp.value = ++value;

        return temp;
    }

    // Overload ++ when used as postfix
    Count operator ++ (int) {
        Count temp;

        // Here, value is the value attribute of the calling object
        temp.value = value++;

        return temp;
    }

    void display() {
        cout << "Count: " << value << endl;
    }
};

int main() {
    Count count1, result;

    // Call the "Count operator ++ ()" function
    result = ++count1;
    result.display();

    // Call the "Count operator ++ (int)" function
    result = count1++;
    result.display();

    return 0;
}

输出

Count: 6
Count: 6

在这里,我们使用以下代码进行前缀运算符重载:

// Overload ++ when used as prefix
Count operator ++ () {
    Count temp;

    // Here, value is the value attribute of the calling object
    temp.value = ++value;

    return temp;
}

后缀运算符重载的代码也类似。注意我们已经创建了一个对象 temp 并将其值返回给运算符函数。

重载二元运算符

二元运算符处理两个操作数。例如,

result = num + 9;

+ 是一个用于 num9 两个操作数的二元运算符。

当我们使用代码重载用户定义类型的二元运算符时:

obj3 = obj1 + obj2;

操作符函数被调用时使用对象 obj1obj2 作为参数传递给函数。

示例 4:C++ 二元运算符重载

#include <iostream>
using namespace std;

class Complex {
   private:
    float real;
    float imag;

   public:
    // Constructor to initialize real and imag to 0
    Complex() : real(0), imag(0) {}

    void input() {
        cout << "Enter real and imaginary parts respectively: ";
        cin >> real;
        cin >> imag;
    }

    // Overload the + operator
    Complex operator + (const Complex& obj) {
        Complex temp;
        temp.real = real + obj.real;
        temp.imag = imag + obj.imag;
        return temp;
    }

    void output() {
        if (imag < 0)
            cout << "Output Complex number: " << real << imag << "i";
        else
            cout << "Output Complex number: " << real << "+" << imag << "i";
    }
};

int main() {
    Complex complex1, complex2, result;

    cout << "Enter first complex number:\n";
    complex1.input();

    cout << "Enter second complex number:\n";
    complex2.input();

   // complex1 calls the operator function
   // complex2 is passed as an argument to the function
    result = complex1 + complex2;
    result.output();

    return 0;
}

输出

Enter first complex number:
Enter real and imaginary parts respectively: 9 5
Enter second complex number:
Enter real and imaginary parts respectively: 7 6
Output Complex number: 16+11i

在这个程序中,操作符函数是:

Complex operator + (const Complex& obj) {
    // code
}

同样,我们也可以这样使用下面的这个函数:

Complex operator + (Complex obj) {
    // code
}

然而,

  • 使用 & 让我们的代码高效,因为在操作符函数内引用了 complex2 对象而不是创建一个重复的对象。
  • 使用 const 被认为是一种很好的做法,因为它可以防止操作符函数修改 complex2.

C++ 二元运算符重载
C++ 二元运算符重载

在 C++ 运算符重载中要记住的事情

  1. 两个运算符 =& 已经在 C++ 中默认重载。比如复制同一个类的对象,我们可以直接使用 = 操作符。我们不需要创建运算符函数。
  2. 运算符重载不能改变运算符的优先级和结合性。但是,如果我们要更改计算顺序,则应使用括号。
  3. 在 C++ 中有 4 个不能重载的运算符。他们是:
    1. :: (范围解析)
    2. . (成员选择)
    3. .* (通过指向函数的指针选择成员)
    4. ?: (三元运算符)