• c++ 运算符重载(一)


    1. 来源

    什么是c++ 中的运算符?C++中的运算符是用于执行各种操作的特殊符号。下面是一些常见的C++运算符:

    1. 算术运算符:用于执行基本的数学运算,例如加法(+),减法(-),乘法(*),除法(/),取模(%)等。

    2. 关系运算符:用于比较两个值之间的关系,例如等于(==),不等于(!=),大于(>),小于(<),大于等于(>=),小于等于(<=)。

    3. 逻辑运算符:用于组合和操作布尔表达式,例如逻辑与(&&),逻辑或(||),逻辑非(!)。

    4. 位运算符:用于对整数在二进制位级别进行操作,例如按位与(&),按位或(|),按位异或(^),左移位(<<),右移位(>>)。

    5. 赋值运算符:用于将一个值赋给变量,例如简单赋值(=),加等赋值(+=),减等赋值(-=)等。

    6. 条件运算符:也称为三元运算符,在条件满足时返回一个值,语法为条件 ? 值1 : 值2。如果条件成立,则返回值1;否则返回值2。

    7. 自增自减运算符:用于增加或减少变量的值,包括前缀自增(++变量),后缀自增(变量++),前缀自减(–变量),后缀自减(变量–)。

    2. 简介

    运算符重载(Operator Overloading)是指通过定义特定的函数来重新定义已有运算符的行为。运算符重载允许在开发者自定义的类型上使用类似于内置类型的运算符,使得自定义类型能够以更直观和自然的方式进行运算操作。

    3. 特点

    1. 重载后的运算符可以像使用内置运算符一样使用
    2. 通过函数重载实现:运算符重载是通过定义特定的成员函数或非成员函数来实现的,这些函数具有特定的命名规则和参数列表,使得编译器能够在正确的上下文中调用它们
    3. 不能改变运算符的优先级和结合性:运算符重载只能改变运算符的操作数类型和操作行为,不能改变运算符的优先级和结合性。

    4. 定义方式

    定义运算符重载有两种方式,成员函数定义和全局函数定义。
    代码:

    #include 
    
    class Vector {
    
    public:
        int x;
        int y;
    
    
        Vector(int xVal, int yVal) : x(xVal), y(yVal) {}
    
        // 成员函数定义运算符重载
    //    Vector operator+(const Vector& other) const {
    //        return Vector(x + other.x, y + other.y);
    //    }
    
        // 运算符重载:输出向量
        friend std::ostream& operator<<(std::ostream& os, const Vector& v) {
            os << "(" << v.x << ", " << v.y << ")";
            return os;
        }
    };
    
    // 全局函数定义运算符重载
    Vector operator+(const Vector& other0,const Vector& other1)  {
        return Vector(other0.x + other1.x, other0.x + other1.y);
    }
    
    
    int main() {
        Vector v1(1, 2);
        Vector v2(3, 4);
    
        Vector result = v1 + v2;  // 使用运算符+
        std::cout << "Result: " << result << std::endl;  // 使用运算符<<
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    4.1 成员函数定义重载运算符 + (operator+):

    1. 运算符右边的对象就是重载运算符函数的参数
    2. v1 + v2 就会调用 operator+ 函数,相当于 v1.operator+(v2)

    4.2 全局函数定义重载运算符 + (operator+):

    1. 运算符左右两边的对象就是重载运算符函数的参数
    2. v1 + v2 就会调用 operator+ 函数,相当于 operator+(v1,v2)

    4.3 tips

    既然可以成员函数的方式了,为什么还需要有全局函数这种方式?

    成员函数定义的方式就是在类的范畴里面定义,只有不能在类的里面
    定义运算符重载的时候,才需要使用全局函数的方式。一般这种情况出现在,项目使用到了别人已经写好的类,并且这个类的源码无法修改。

    5. 函数调用运算符重载

    5.1 简介

    c++中可以使用对象来访问类中的成员函数,而对象本身是不能像函数一样被调用的,除非在类中重载了函数调用运算符(Function Call Operator)。 如果类重载了函数调用运算符,则我们可以像使用函数一样使用该类的对象。在外面使用 对象(),实际上背后访问的是类中重载的调用运算符函数。

    函数调用的方式

    1. 对象.函数();

    2. 函数名();

    () : 函数调用运算符

    1. 对象();

    如果某个类重载了函数调用运算符,那么该类的对象即可称之为:函数对象 ,因为可以调用这种对象,所以才说这些对象行为 像函数一样

    代码:

    #include 
    
    class Adder {
    public:
        int add(int x, int y){
            return x + y;
        }
        int operator()(int x, int y) const {
            return x + y;
        }
    };
    
    int main() {
    
        Adder adder;
    
        int result0 = adder.add(1, 2); //对象调用成员函数
        std::cout << "Result0: " << result0 << std::endl;
    
        int result1 = adder(3, 4);  // 调用函数对象
        std::cout << "Result1: " << result1 << std::endl;
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    5.2 标准库中的函数对象

    标准库中定义了一组算术运算符 、关系运算符、逻辑运算符的类,每个类都有自己重载的调用运算符。要想使用这些类,需要导入 #include , 其中 lamdda表达式 也是一个函数对象

    #include 
    #include
    
    using namespace std;
    
    int main(){
    
        plus<int > p; //加法
        int a = p(4, 7);
        cout << a << std::endl;
    
        negate<int> n; //绝对值
        std::cout <<n(-2) << std::endl;
    
        return 0 ;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    其中 std::plus p;p(4, 7) 也是标准库 functional 的对象:

    // STRUCT TEMPLATE plus
    template <class _Ty = void>
    struct plus {
        _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty _FIRST_ARGUMENT_TYPE_NAME;
        _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty _SECOND_ARGUMENT_TYPE_NAME;
        _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty _RESULT_TYPE_NAME;
    
        _NODISCARD constexpr _Ty operator()(const _Ty& _Left, const _Ty& _Right) const {
            return _Left + _Right;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    5.3 注意点

    1. 函数调用运算符重载不改变对象的类型:函数调用运算符重载只是改变了对象的行为,而不改变对象的类型。对象仍然是类的实例,只是通过函数调用运算符的重载,使其能够像函数一样被调用。
    2. 函数重载的替代:有时候可以使用函数调用运算符重载来替代函数重载。当函数的参数数量或类型不同导致函数重载不够灵活时,可以考虑使用函数调用运算符重载来实现更灵活的函数调用方式。
  • 相关阅读:
    SpringBoot 学习(八)异步任务,邮件发送和定时执行
    门店管理系统、店铺管理软件不要随便买,看好这几个标准才能放心用!
    温故而知新六(C++)
    附录5-vscode常用配置
    Spring基础:依赖注入
    【QML】QML性能优化 | 3D场景优化
    1907_Arm Cortex-M3的基本了解
    亚商投资顾问 早餐FM/0913
    VUE 组合式API
    CSS特效007:绘制3D文字,类似PS效果
  • 原文地址:https://blog.csdn.net/weixin_40378209/article/details/133818518