操作符重载概述

参考:Operator overloading

使用关键字operator声明函数,可以指定当应用于类实例时该运算符符号(operator-symbol)的含义。可以为运算符设置多个含义(也可以称为重载),编译器通过检查操作数的类型来区分运算符的不同含义

语法

可以在类内或全局作用域内重定义大多数运算符,运算符重载声明如下:

type operator operator-symbol ( parameter-list )

重载的运算符被看成函数,比如重载加法运算符,相当于调用函数operator+;重载加法赋值运算符,相当于调用函数operator+=

可被重定义的运算符列表参考:Redefinable Operators

不可被重定义的运算符列表参考:Nonredefinable Operators

分类

按操作数和作用方式的不同可分类重载运算符如下:

  1. 一元运算符(unary operatiors
  2. 二元运算符(binary operations
  3. 赋值运算符(assignment
  4. 函数调用(function call
  5. 下标(subscripting
  6. 类成员访问(class-member access
  7. 递增和递减(increment and decrement
  8. 用户自定义类型转换(user-defined type conversion

使用

重载后的运算符函数可以隐式通过运算符号进行调用,也可以显式调用运算符函数进行操作。定义类Complex并重载加法运算符

struct Complex {
    Complex(double r, double i) : re(r), im(i) {}

    Complex operator+(Complex &other);

    void Display() { cout << re << ", " << im << endl; }

private:
    double re, im;
};

// Operator overloaded using a member function
Complex Complex::operator+(Complex &other) {
    return Complex{re + other.re, im + other.im};
}

int main() {
    Complex a = Complex(1.2, 3.4);
    Complex b = Complex(5.6, 7.8);
    Complex c = Complex(0.0, 0.0);

    // 隐式调用
    Complex d = a + b;
    // 隐式调用
    Complex e = c.operator+(d);
    e.Display();
}

通用规则

参考:General Rules for Operator Overloading

以下规则约束如何实现重载运算符。但是它们不适用于newdelete,这两个操作符将分别介绍

  • 不能定义新运算符
  • 当应用于内置数据类型时,不能重定义运算符的含义
  • 重载运算符只能是全局函数或者非静态成员函数
    • 如果全局函数需要访问类privateprotected成员,必须声明为该类的友元函数
    • 全局函数至少有一个参数是类或枚举类型,或者是它们的引用类型
  • 运算符遵循由内置类型的典型使用决定的优先级、分组和操作数数量。因此,无法实现向Point类型的对象添加2和3的概念,除非将2添加到X坐标,将3添加到Y坐标
  • 一元运算符如果声明为成员函数,没有参数;如果声明为全局函数,需要一个参数
  • 二元运算符如果声明为成员函数,需要一个参数;如果声明为全局函数,需要二个参数
  • 如果运算符既可以声明为一元,也可以声明为二元,比如&/*/+/-,可以分别重载
  • 重载运算符没有默认参数
  • 所有重载运算符(除了赋值运算符operator=以外)都可以被继承
  • 成员函数重载运算符的第一个参数始终是调用该运算符的对象的类类型(声明该运算符的类或从该类派生的类),不能为第一个参数提供转换