Skip to content

C++ 重载运算符和重载函数

重载是 C++ 的一个重要特性,它允许为同一个函数名或运算符定义多个版本,以适应不同的参数类型或操作数类型。

1. 函数重载

函数重载是指在同一个作用域内定义多个同名函数,但它们的参数列表不同。

1.1 基本示例

cpp
#include <iostream>

int add(int a, int b) {
    return a + b;
}

double add(double a, double b) {
    return a + b;
}

std::string add(std::string a, std::string b) {
    return a + b;
}

int main() {
    std::cout << "10 + 20 = " << add(10, 20) << std::endl;
    std::cout << "10.5 + 20.5 = " << add(10.5, 20.5) << std::endl;
    std::cout << "Hello + World = " << add(std::string("Hello"), std::string("World")) << std::endl;
    
    return 0;
}

1.2 参数个数不同

cpp
#include <iostream>

int sum(int a) {
    return a;
}

int sum(int a, int b) {
    return a + b;
}

int sum(int a, int b, int c) {
    return a + b + c;
}

int main() {
    std::cout << "sum(10) = " << sum(10) << std::endl;
    std::cout << "sum(10, 20) = " << sum(10, 20) << std::endl;
    std::cout << "sum(10, 20, 30) = " << sum(10, 20, 30) << std::endl;
    
    return 0;
}

1.3 参数类型不同

cpp
#include <iostream>

void print(int num) {
    std::cout << "整数: " << num << std::endl;
}

void print(double num) {
    std::cout << "浮点数: " << num << std::endl;
}

void print(std::string str) {
    std::cout << "字符串: " << str << std::endl;
}

int main() {
    print(10);
    print(10.5);
    print("Hello");
    
    return 0;
}

2. 运算符重载

运算符重载是指为用户自定义的类型(类)重新定义运算符的行为。

2.1 重载算术运算符

cpp
#include <iostream>

class Complex {
private:
    double real;
    double imag;

public:
    Complex(double real = 0, double imag = 0) : real(real), imag(imag) {}
    
    Complex operator+(const Complex& other) {
        return Complex(real + other.real, imag + other.imag);
    }
    
    Complex operator-(const Complex& other) {
        return Complex(real - other.real, imag - other.imag);
    }
    
    Complex operator*(const Complex& other) {
        return Complex(real * other.real - imag * other.imag, 
                       real * other.imag + imag * other.real);
    }
    
    void print() {
        std::cout << real << " + " << imag << "i" << std::endl;
    }
};

int main() {
    Complex c1(1.0, 2.0);
    Complex c2(3.0, 4.0);
    
    Complex c3 = c1 + c2;
    Complex c4 = c1 - c2;
    Complex c5 = c1 * c2;
    
    std::cout << "c1 + c2 = ";
    c3.print();
    
    std::cout << "c1 - c2 = ";
    c4.print();
    
    std::cout << "c1 * c2 = ";
    c5.print();
    
    return 0;
}

2.2 重载关系运算符

cpp
#include <iostream>

class Point {
private:
    int x;
    int y;

public:
    Point(int x = 0, int y = 0) : x(x), y(y) {}
    
    bool operator==(const Point& other) {
        return x == other.x && y == other.y;
    }
    
    bool operator!=(const Point& other) {
        return !(*this == other);
    }
    
    bool operator<(const Point& other) {
        return x < other.x || (x == other.x && y < other.y);
    }
    
    void print() {
        std::cout << "(" << x << ", " << y << ")" << std::endl;
    }
};

int main() {
    Point p1(1, 2);
    Point p2(1, 2);
    Point p3(3, 4);
    
    std::cout << "p1 == p2: " << (p1 == p2) << std::endl;
    std::cout << "p1 != p2: " << (p1 != p2) << std::endl;
    std::cout << "p1 < p3: " << (p1 < p3) << std::endl;
    
    return 0;
}

2.3 重载输入输出运算符

cpp
#include <iostream>

class Point {
private:
    int x;
    int y;

public:
    Point(int x = 0, int y = 0) : x(x), y(y) {}
    
    friend std::ostream& operator<<(std::ostream& os, const Point& point);
    friend std::istream& operator>>(std::istream& is, Point& point);
};

std::ostream& operator<<(std::ostream& os, const Point& point) {
    os << "(" << point.x << ", " << point.y << ")";
    return os;
}

std::istream& operator>>(std::istream& is, Point& point) {
    is >> point.x >> point.y;
    return is;
}

int main() {
    Point point(10, 20);
    
    std::cout << "point = " << point << std::endl;
    
    std::cout << "请输入点的坐标(x y): ";
    std::cin >> point;
    std::cout << "point = " << point << std::endl;
    
    return 0;
}

2.4 重载赋值运算符

cpp
#include <iostream>

class String {
private:
    char* data;
    size_t size;

public:
    String(const char* str = "") {
        size = strlen(str);
        data = new char[size + 1];
        strcpy(data, str);
    }
    
    String(const String& other) {
        size = other.size;
        data = new char[size + 1];
        strcpy(data, other.data);
    }
    
    String& operator=(const String& other) {
        if (this != &other) {
            delete[] data;
            size = other.size;
            data = new char[size + 1];
            strcpy(data, other.data);
        }
        return *this;
    }
    
    ~String() {
        delete[] data;
    }
    
    void print() {
        std::cout << data << std::endl;
    }
};

int main() {
    String str1("Hello");
    String str2("World");
    
    std::cout << "str1: ";
    str1.print();
    
    std::cout << "str2: ";
    str2.print();
    
    str1 = str2;
    
    std::cout << "赋值后 str1: ";
    str1.print();
    
    return 0;
}

2.5 重载下标运算符

cpp
#include <iostream>

class Array {
private:
    int* data;
    size_t size;

public:
    Array(size_t size) : size(size) {
        data = new int[size];
    }
    
    int& operator[](size_t index) {
        return data[index];
    }
    
    const int& operator[](size_t index) const {
        return data[index];
    }
    
    ~Array() {
        delete[] data;
    }
};

int main() {
    Array arr(5);
    
    for (size_t i = 0; i < 5; i++) {
        arr[i] = i * 10;
    }
    
    for (size_t i = 0; i < 5; i++) {
        std::cout << arr[i] << " ";
    }
    std::cout << std::endl;
    
    return 0;
}

3. 运算符重载的规则

3.1 可以重载的运算符

以下运算符可以被重载:

  • 算术运算符:+-*/%
  • 关系运算符:==!=<><=>=
  • 逻辑运算符:&&||!
  • 位运算符:&|^~<<>>
  • 赋值运算符:=+=-=*=/=%=&=|=^=<<=>>=
  • 自增自减运算符:++--
  • 下标运算符:[]
  • 函数调用运算符:()
  • 成员访问运算符:->
  • 逗号运算符:,
  • 内存管理运算符:newdeletenew[]delete[]

3.2 不能重载的运算符

以下运算符不能被重载:

  • 成员访问运算符:.
  • 成员指针访问运算符:.*
  • 作用域解析运算符:::
  • 条件运算符:?:
  • sizeof运算符
  • typeid运算符

3.3 重载运算符的规则

  1. 不能创建新的运算符
  2. 不能改变运算符的优先级
  3. 不能改变运算符的操作数个数
  4. 至少有一个操作数是用户自定义的类型
  5. 重载运算符时,应该保持运算符的原始含义

4. 示例:综合运用

现在,让我们看一个综合运用各种重载特性的例子:

cpp
#include <iostream>
#include <cmath>

class Complex {
private:
    double real;
    double imag;

public:
    Complex(double real = 0, double imag = 0) : real(real), imag(imag) {}
    
    Complex operator+(const Complex& other) {
        return Complex(real + other.real, imag + other.imag);
    }
    
    Complex operator-(const Complex& other) {
        return Complex(real - other.real, imag - other.imag);
    }
    
    Complex operator*(const Complex& other) {
        return Complex(real * other.real - imag * other.imag, 
                       real * other.imag + imag * other.real);
    }
    
    Complex operator/(const Complex& other) {
        double denominator = other.real * other.real + other.imag * other.imag;
        return Complex((real * other.real + imag * other.imag) / denominator,
                       (imag * other.real - real * other.imag) / denominator);
    }
    
    bool operator==(const Complex& other) {
        return real == other.real && imag == other.imag;
    }
    
    bool operator!=(const Complex& other) {
        return !(*this == other);
    }
    
    double magnitude() {
        return sqrt(real * real + imag * imag);
    }
    
    friend std::ostream& operator<<(std::ostream& os, const Complex& complex);
    friend std::istream& operator>>(std::istream& is, Complex& complex);
};

std::ostream& operator<<(std::ostream& os, const Complex& complex) {
    if (complex.imag >= 0) {
        os << complex.real << " + " << complex.imag << "i";
    } else {
        os << complex.real << " - " << -complex.imag << "i";
    }
    return os;
}

std::istream& operator>>(std::istream& is, Complex& complex) {
    is >> complex.real >> complex.imag;
    return is;
}

int main() {
    Complex c1(1.0, 2.0);
    Complex c2(3.0, 4.0);
    
    std::cout << "c1 = " << c1 << std::endl;
    std::cout << "c2 = " << c2 << std::endl;
    std::cout << std::endl;
    
    Complex c3 = c1 + c2;
    std::cout << "c1 + c2 = " << c3 << std::endl;
    
    Complex c4 = c1 - c2;
    std::cout << "c1 - c2 = " << c4 << std::endl;
    
    Complex c5 = c1 * c2;
    std::cout << "c1 * c2 = " << c5 << std::endl;
    
    Complex c6 = c1 / c2;
    std::cout << "c1 / c2 = " << c6 << std::endl;
    std::cout << std::endl;
    
    std::cout << "c1 == c2: " << (c1 == c2) << std::endl;
    std::cout << "c1 != c2: " << (c1 != c2) << std::endl;
    std::cout << std::endl;
    
    std::cout << "|c1| = " << c1.magnitude() << std::endl;
    std::cout << "|c2| = " << c2.magnitude() << std::endl;
    std::cout << std::endl;
    
    Complex c7;
    std::cout << "请输入复数(实部 虚部): ";
    std::cin >> c7;
    std::cout << "你输入的复数是: " << c7 << std::endl;
    
    return 0;
}

小结

C++ 重载运算符和重载函数包括:

  1. 函数重载

    • 在同一个作用域内定义多个同名函数
    • 参数列表不同(参数个数、参数类型、参数顺序)
  2. 运算符重载

    • 为用户自定义的类型重新定义运算符的行为
    • 重载算术运算符:+-*/%
    • 重载关系运算符:==!=<><=>=
    • 重载输入输出运算符:<<>>
    • 重载赋值运算符:=
    • 重载下标运算符:[]
  3. 运算符重载的规则

    • 可以重载的运算符
    • 不能重载的运算符
    • 重载运算符的规则

关键概念:

  • 函数重载:在同一个作用域内定义多个同名函数,但参数列表不同
  • 运算符重载:为用户自定义的类型重新定义运算符的行为
  • 友元函数:可以访问类的私有成员
  • 成员函数:作为类的成员函数重载运算符

掌握重载是 C++ 面向对象编程的重要基础,在后续章节中,我们将学习 C++ 的多态。