跳转到内容

C++ 一元运算符重载

来自代码酷

C++一元运算符重载[编辑 | 编辑源代码]

一元运算符是仅作用于单个操作数的运算符。在C++中,可以通过运算符重载来为用户自定义类型(如类或结构体)定义这些运算符的行为。本篇文章将详细介绍如何在C++中重载一元运算符。

介绍[编辑 | 编辑源代码]

一元运算符重载允许程序员为自定义类型定义运算符的行为。常见的一元运算符包括:

  • 递增(++)和递减(--)
  • 正号(+)和负号(-)
  • 逻辑非(!)
  • 按位取反(~)
  • 取地址(&)和解引用(*)

重载一元运算符可以通过成员函数或非成员函数(通常是友元函数)实现。成员函数形式更为常见,因为它能直接访问类的私有成员。

语法[编辑 | 编辑源代码]

一元运算符重载的通用语法如下:

  • 成员函数形式:
返回类型 operator运算符符号() {
    // 实现
}
  • 非成员函数形式:
返回类型 operator运算符符号(参数类型) {
    // 实现
}

示例:重载递增运算符[编辑 | 编辑源代码]

下面是一个重载前缀和后缀递增运算符的示例:

#include <iostream>

class Counter {
private:
    int count;
public:
    Counter(int c = 0) : count(c) {}
    
    // 前缀++重载(成员函数)
    Counter& operator++() {
        ++count;
        return *this;
    }
    
    // 后缀++重载(成员函数)
    Counter operator++(int) {
        Counter temp = *this;
        ++count;
        return temp;
    }
    
    void display() const {
        std::cout << "Count: " << count << std::endl;
    }
};

int main() {
    Counter c1(5);
    
    // 前缀++
    ++c1;
    c1.display();  // 输出: Count: 6
    
    // 后缀++
    Counter c2 = c1++;
    c1.display();  // 输出: Count: 7
    c2.display();  // 输出: Count: 6
    
    return 0;
}

示例:重载负号运算符[编辑 | 编辑源代码]

下面展示如何重载负号运算符:

#include <iostream>

class Distance {
private:
    int meters;
public:
    Distance(int m = 0) : meters(m) {}
    
    // 重载负号运算符
    Distance operator-() const {
        return Distance(-meters);
    }
    
    void display() const {
        std::cout << "Distance: " << meters << "m" << std::endl;
    }
};

int main() {
    Distance d1(10);
    Distance d2 = -d1;
    
    d1.display();  // 输出: Distance: 10m
    d2.display();  // 输出: Distance: -10m
    
    return 0;
}

成员函数 vs 非成员函数[编辑 | 编辑源代码]

下表比较了两种重载方式的区别:

erDiagram OPERATOR_OVERLOADING { string 方式 string 访问权限 string 参数数量 string 示例 } OPERATOR_OVERLOADING { "成员函数" : "方式" "可以访问私有成员" : "访问权限" "无显式参数" : "参数数量" "Counter::operator++()" : "示例" } OPERATOR_OVERLOADING { "非成员函数" : "方式" "需要友元声明" : "访问权限" "一个参数" : "参数数量" "operator-(Distance)" : "示例" }

实际应用案例[编辑 | 编辑源代码]

考虑一个表示复数的类,我们可以重载一元运算符来实现各种操作:

#include <iostream>
#include <cmath>

class Complex {
private:
    double real, imag;
public:
    Complex(double r = 0, double i = 0) : real(r), imag(i) {}
    
    // 重载正号运算符(通常返回副本)
    Complex operator+() const {
        return *this;
    }
    
    // 重载负号运算符
    Complex operator-() const {
        return Complex(-real, -imag);
    }
    
    // 重载逻辑非运算符(判断是否为零)
    bool operator!() const {
        return (real == 0) && (imag == 0);
    }
    
    void display() const {
        std::cout << real << (imag >= 0 ? "+" : "") << imag << "i" << std::endl;
    }
};

int main() {
    Complex c1(3, 4);
    Complex c2 = -c1;
    
    c1.display();  // 输出: 3+4i
    c2.display();  // 输出: -3-4i
    
    if (!Complex(0, 0)) {
        std::cout << "Zero complex number" << std::endl;
    }
    
    return 0;
}

注意事项[编辑 | 编辑源代码]

1. 不能创建新的运算符,只能重载现有的C++运算符 2. 不能改变运算符的优先级和结合性 3. 某些运算符(如?:、::、.、.*等)不能被重载 4. 重载运算符时,至少有一个操作数必须是用户定义类型 5. 保持运算符的直观含义,避免令人困惑的实现

数学表示[编辑 | 编辑源代码]

对于复数类的负号运算符重载,可以用数学表示为: (a+bi)=abi

其中a是实部,b是虚部。

总结[编辑 | 编辑源代码]

一元运算符重载是C++中强大的特性,允许自定义类型像内置类型一样使用运算符。通过合理使用运算符重载,可以使代码更直观、更易读。记住要保持运算符的语义清晰,并遵循运算符重载的最佳实践。