开发者

C++类和对象之运算符重载解读

目录
  • C++ 运算符重载
    • 一、什么是运算符重载?
    • 二、运算符重载的语法规则
      • 成员函数重载
      • 非成员函数重载
      • 赋值运算符重载
      • 取地址运算符重载
    • 三、可重载的运算符和不可重载的运算符
      • 可重载的运算符
      • 不可重载的运算符
    • 五、运算符重载的注意事项
    • 总结

      C++ 运算符重载

      一、什么是运算符重载?

      运算符重载是 C++ 的一种特性,它允许程序员为自定义类型(如类和结构体)重新定义运算符的行为。通过运算符重载,我们可以使用熟悉的运算符语法来操作自定义类型的对象,从而使代码更加简洁、直观。

      当运算符被⽤于类类型的对象时,C++语⾔允许我们通过运算符重载的形式指定新的含义。C++规定类类型对象使⽤运算符时,必须转换成调⽤对应运算符重载,若没有对应的运算符重载,则会编译报错。

      例如,我们可以为自定义的复数类重载 + 运算符,使得两个复数对象可以直接使用 + 进行相加:

      Complex a(1, 2);
      Complex b(3, 4);
      Complex c = a + b; // 使用重载的 + 运算符

      二、运算符重载的语法规则

      在 C++ 中,运算符重载通过定义特殊的成员函数或非成员函数来实现。

      其基本语法如下:

      返回类型 operator运算符(参数列表) {
          // 函数体
      }

      其中:

      • operator 是 C++ 的关键字,用于声明一个运算符重载函数。
      • 运算符 是要重载的运算符,如 +, -, *, / 等。
      • 返回类型 是运算符重载函数的返回值类型,通常与操作数的类型相关。
      • 参数列表 是运算符重载函数的参数,参数的个数和类型取决于运算符的种类和重载方式。

      注意:

      • ⼀个类需要重载哪些运算符,是看哪些运算符重载后有意义
      • 重载++运算符时,有前置++和后置++,运算符重载函数名都是operator++,⽆法很好的区分。C++规定,后置++重载时,增加⼀个int形参,跟前置++构成函数重载,⽅便区分。
      • 当运算符被⽤于类类型的对象时,C++语⾔允许我们通过运算符重载的形式指定新的含义。C++规定类类型对象使⽤运算符时,必须转换成调⽤对应运算符重载,若没有对应的运算符重载,则会编译报错。
      • 运算符重载是具有特殊名字的函数,他的名字是由operator和后⾯要定义的运算符共同构成。和其他函数⼀样,它也具有其返回类型和参数列表以及函数体。
      • 重载运算符函数的参数个数和该运算符作⽤的运算对象数量⼀样多。⼀元运算符有⼀个参数,⼆元运算符有两个参数,⼆元运算符的左侧运算对象传给第⼀个参数,右侧运算对象传给第⼆个参数。
      • 如果⼀个重载编程客栈运算符函数是成员函数,则它的第⼀个运算对象默认传给隐式的this指针,因此运算符重载作为成员函数时,参数⽐运算对象少⼀个。
      • 运算符重载以后,其优先级和结合性与对应的内置类型运算符保持⼀致。
      • 不能通过连接语法中没有的符号来创建新的操作符:⽐如operator@。

      重载<<和>>时,需要重载为全局函数,因为重载为成员函数,this指针默认抢占了第⼀个形参位置,第⼀个形参位置是左侧运算对象,调⽤时就变成了 对象<<cout,不符合使⽤习惯和可读性。

      重载为全局函数把ostream/istream放到第⼀个形参位置就可以了,第⼆个形参位置当类类型对象。

      成员函数重载

      运算符重载函数可以作为类的成员函数来定义。在这种情况下,函数的参数个数比运算符的操作数少一个,因为第一个操作数是通过 this 指针隐式传递的。

      非成员函数重载

      运算符重载函数也可以作为非成员函数(全局函数或友元函数)来定义。

      在这种情况下,函数的参数个数与运算符的操作数相同。

      赋值运算符重载

      赋值运算符重载是⼀个默认成员函数,⽤于完android成两个已经存在的对象直接的拷⻉赋值,这⾥要注意跟拷⻉构造区分,拷⻉构造⽤于⼀个对象拷⻉初始化给另⼀个要创建的对象。

      赋值运算符重载的特点:

      • 赋值运算符重载是⼀个运算符重载,规定必须重载为成员函数。赋值运算重载的参数建议写成const当前类类型引⽤,否则会传值传参会有拷⻉
      • 有返回值,且建议写成当前类类型引⽤,引⽤返回可以提⾼效率,有返回值⽬的是为了⽀持连续赋值场景。
      • 没有显式实现时,编译器会⾃动⽣成⼀个默认赋值运算符重载,默认赋值运算符重载⾏为跟默认拷⻉构造编程客栈函数类似,对内置类型成员变量会完成值拷⻉/浅拷⻉(⼀个字节⼀个字节的拷⻉),对⾃定义类型成员变量会调⽤他的赋值重载函数。

      拷贝构造:一个存在的对象去初始化另一个要实例化的对象; 赋值重载:已存在的两个对象之间的拷贝,注意返回值为类类型,处理连续赋值的情况

      取地址运算符重载

      const成员函数

      • 将const修饰的成员函数称之为const成员函数,const修饰成员函数放到成员函数参数列表的后⾯。
      • const实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进⾏修改。Date* const this 变为 const Date* const this

      取地址运算符重载

      • 取地址运算符重载分为普通取地址运算符重载和const取地址运算符重载,⼀般这两个函数编译器⾃动⽣成的就可以够我们⽤了,不需要去显⽰实现。
      • 除⾮⼀些很特殊的场景,⽐如我们不想让别⼈取到当前类对象的地址,就可以⾃⼰实现⼀份,胡乱返回⼀个地址。

      三、可重载的运算符和不编程客栈可重载的运算符

      可重载的运算符

      C++ 中大部分运算符都可以被重载,包括:

      • 算术运算符:+, -, *, /, %, ++, --
      • 比较运算符:==, !=, <, >, <=, >=
      • 逻辑运算符:&&, ||, !
      • 位运算符:&, |, ^, ~, <<, >>
      • 赋值运算符:=, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=
      • 其他运算符:[], (), ->, ,, *(解引用), &(取地址)

      不可重载的运算符

      C++ 中少数运算符不能被重载,包括:

      • 作用域解析运算符:::
      • 成员访问运算符:..*
      • 条件运算符:?:
      • 类型转换运算符:typeiddynamic_cast
      • 编译时运算符:sizeof

      五、运算符重载的注意事项

      在使用运算符重载时,需要注意以下几点:

      • 遵循运算符的原有语义:运算符重载应该保持运算符原有的语义,避免python造成混淆。例如,重载 + 运算符应该实现加法的语义,而不是减法。
      • 不要滥用运算符重载:虽然运算符重载可以使代码更加简洁,但过度使用或滥用会使代码变得难以理解和维护。
      • 保持运算符的优先级和结合性:运算符重载不能改变运算符的优先级和结合性,这是由语言规定的。
      • 正确处理 const 对象:如果运算符重载函数不修改对象的状态,应该将其声明为 const 成员函数。
      • 注意内存管理:在重载赋值运算符和拷贝构造函数时,需要特别注意深拷贝和浅拷贝的问题,避免内存泄漏。
      • 避免创建新的运算符:C++ 不允许创建新的运算符,只能重载已有的运算符。

      总结

      以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。

      0

      上一篇:

      下一篇:

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      最新开发

      开发排行榜