8.2 运算符重载

8.2 运算符重载

运算符重载是C++语言中一种重要的特性,它使得我们能够重新定义已有运算符的意义,使其能够用于特定类的对象执行特定的功能。通过运算符重载,可以实现复杂数据类型的加减乘除等操作,极大地增强了C++语言的扩展能力。

8.2.1 运算符重载的几个问题

在讨论运算符重载时,需要了解以下几个常见问题:

允许重载的运算符

以下运算符是允许重载的:

  • 算术运算符:+, -, *, /, %, ++, --
  • 位操作运算符:&, |, ~, ^, <<, >>
  • 逻辑运算符:!, &&, ||
  • 比较运算符:>, <, >=, <=, ==, !=
  • 赋值运算符:=, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=
  • 其他运算符:[], (), ->, ->*, new, delete, new[], delete[]

以下运算符不允许重载:::, .*, ?:, .

运算符的优先级和结合性

重载运算符不会改变原运算符的优先级和结合性,也不会改变运算符的操作数个数和语法结构。单目运算符只能重载为单目运算符,双目运算符只能重载为双目运算符。

编译程序如何选择运算符函数

编译程序对运算符重载的选择,遵循函数重载的选择原则,主要根据运算符的操作数的类型、个数和顺序进行选择。

运算符重载的限制

运算符重载有以下限制:

  1. 不可臆造新的运算符,必须在C++已有的运算符范围内。
  2. 重载运算符坚持四个“不能改变”:
    • 不能改变运算符操作数的个数。
    • 不能改变运算符原有的优先级。
    • 不能改变运算符原有的结合性。
    • 不能改变运算符原有的语法结构。
运算符重载的原则

运算符重载应使程序更加简洁和直观,但不宜过多使用,以免带来理解上的困难。重载运算符含义必须清楚,避免二义性。

8.2.2 运算符重载函数的两种形式

运算符重载函数有两种常见形式:成员函数形式和友元函数形式。这两种形式都可以访问类中的私有成员。

成员函数形式

以下是一个复数类中重载四则运算运算符的例子:

#include <iostream>
using namespace std;

class Complex {
public:
    Complex() { real = imag = 0; }
    Complex(double r, double i) { real = r; imag = i; }
    Complex operator +(const Complex &c);
    Complex operator -(const Complex &c);
    Complex operator *(const Complex &c);
    Complex operator /(const Complex &c);
    friend void print(const Complex &c);

private:
    double real, imag;
};

Complex Complex::operator +(const Complex &c) {
    return Complex(real + c.real, imag + c.imag);
}

Complex Complex::operator -(const Complex &c) {
    return Complex(real - c.real, imag - c.imag);
}

Complex Complex::operator *(const Complex &c) {
    return Complex(real * c.real - imag * c.imag, real * c.imag + imag * c.real);
}

Complex Complex::operator /(const Complex &c) {
    double denominator = c.real * c.real + c.imag * c.imag;
    return Complex((real * c.real + imag * c.imag) / denominator, 
                   (imag * c.real - real * c.imag) / denominator);
}

void print(const Complex &c) {
    if (c.imag < 0)
        cout << c.real << c.imag << "i";
    else
        cout << c.real << "+" << c.imag << "i";
}

int main() {
    Complex c1(2.0, 3.0), c2(4.0, -2.0), c3;
    c3 = c1 + c2; cout << "\nc1 + c2 = "; print(c3);
    c3 = c1 - c2; cout << "\nc1 - c2 = "; print(c3);
    c3 = c1 * c2; cout << "\nc1 * c2 = "; print(c3);
    c3 = c1 / c2; cout << "\nc1 / c2 = "; print(c3);
    return 0;
}
友元函数形式

将上例改为友元函数形式:

#include <iostream>
using namespace std;

class Complex {
public:
    Complex() { real = imag = 0; }
    Complex(double r, double i) { real = r; imag = i; }
    friend Complex operator +(const Complex &c1, const Complex &c2);
    friend Complex operator -(const Complex &c1, const Complex &c2);
    friend Complex operator *(const Complex &c1, const Complex &c2);
    friend Complex operator /(const Complex &c1, const Complex &c2);
    friend void print(const Complex &c);

private:
    double real, imag;
};

Complex operator +(const Complex &c1, const Complex &c2) {
    return Complex(c1.real + c2.real, c1.imag + c2.imag);
}

Complex operator -(const Complex &c1, const Complex &c2) {
    return Complex(c1.real - c2.real, c1.imag - c2.imag);
}

Complex operator *(const Complex &c1, const Complex &c2) {
    return Complex(c1.real * c2.real - c1.imag * c2.imag, 
                   c1.real * c2.imag + c1.imag * c2.real);
}

Complex operator /(const Complex &c1, const Complex &c2) {
    double denominator = c2.real * c2.real + c2.imag * c2.imag;
    return Complex((c1.real * c2.real + c1.imag * c2.imag) / denominator, 
                   (c1.imag * c2.real - c1.real * c2.imag) / denominator);
}

void print(const Complex &c) {
    if (c.imag < 0)
        cout << c.real << c.imag << "i";
    else
        cout << c.real << "+" << c.imag << "i";
}

int main() {
    Complex c1(2.0, 3.0), c2(4.0, -2.0), c3;
    c3 = c1 + c2; cout << "\nc1 + c2 = "; print(c3);
    c3 = c1 - c2; cout << "\nc1 - c2 = "; print(c3);
    c3 = c1 * c2; cout << "\nc1 * c2 = "; print(c3);
    c3 = c1 / c2; cout << "\nc1 / c2 = "; print(c3);
    return 0;
}

8.2.3 其他运算符的重载举例

重载下标运算符
#include <iostream>
using namespace std;

class CharArray {
public:
    CharArray(int l) {
        Length = l;
        Buff = new char[Length];
    }
    ~CharArray() { delete[] Buff; }
    int GetLength() { return Length; }
    char& operator [](int i);

private:
    int Length;
    char *Buff;
};

char& CharArray::operator [](int i) {
    static char ch = 0;
    if (i < Length && i >= 0)
        return Buff[i];
    else {
        cout << "\nIndex out of range.";
        return ch;
    }
}

int main() {
    CharArray string1(6);
    char *string2 = "string";
    for (int cnt = 0; cnt < 8; cnt++)
        string1[cnt] = string2[cnt];
    cout << "\n";
    for (int cnt = 0; cnt < 8; cnt++)
        cout << string1[cnt];
    cout << "\n";
    cout << string1.GetLength() << endl;
    return 0;
}
重载增1减1运算符
#include <iostream>
using namespace std;

class Counter {
public:
    Counter() { v = 0; }
    Counter operator ++();
    Counter operator ++(int);
    void print() { cout << v << endl; }

private:
    unsigned v;
};

Counter Counter::operator ++() {
    v++;
    return *this;
}

Counter Counter::operator ++(int) {
       Counter t = *this;
    v++;
    return t;
}

int main() {
    Counter c;
    for (int i = 0; i < 8; i++)
        ++c;
    c.print();
    for (int i = 0; i < 8; i++)
        c++;
    c.print();
    return 0;
}

说明

  • 在该程序中,类 Counter 定义了两个重载的增1运算符函数:Counter operator++() 为前缀运算符,而 Counter operator++(int) 为后缀运算符。
  • 前缀运算符直接增加计数器的值并返回自身的引用。
  • 后缀运算符首先保存当前对象的副本,然后增加计数器的值,最后返回保存的副本。
重载函数调用运算符
#include <iostream>
using namespace std;

class F {
public:
    double operator()(double x, double y) const;
};

double F::operator()(double x, double y) const {
    return (x + 5) * y;
}

int main() {
    F f;
    cout << f(1.5, 2.2) << endl;
    return 0;
}

说明

  • 在该程序中,重载了函数调用运算符 operator().
  • 该运算符实现了一个简单的数学函数 (x + 5) * y
  • 使用 f(1.5, 2.2) 进行调用时,实际调用的是 f.operator()(1.5, 2.2)

总结

运算符重载是C++语言中的一个强大特性,能够使程序更加简洁和易读。通过重载运算符,可以实现自定义数据类型的自然操作,如复数的加减乘除、数组的安全访问等。在运算符重载时,需要注意以下几点:

  • 重载运算符应保持其原有的优先级和结合性。
  • 重载运算符的含义应清晰明确,避免二义性。
  • 根据需求选择合适的重载形式,成员函数形式和友元函数形式各有优缺点。

通过合理使用运算符重载,可以极大地提高程序的可读性和可维护性,同时也增强了C++语言的表达能力。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏驰和徐策

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值