博客
关于我
C++ primer学习笔记 第十四章 重载运算与类型转换
阅读量:677 次
发布时间:2019-03-16

本文共 2809 字,大约阅读时间需要 9 分钟。

重载运算符在C++中的基础概念

重载运算符是C++中一个强大特性,它允许我们自定义类的运算行为。通过重载运算符,我们可以为用户定义的类增加和内置类型相同的操作符功能,从而使其更加灵活和可扩展。

运算符的定义和使用

重载运算符的定义方式有以下两种:

  • 通过 operator 关键字定义

    例如,定义一个加法运算符可以这样写:

    int operator+(const MyObject& a, const MyObject& b) {    return a + b;}
  • 直接定义

    有时候,如果运算符已经是成员函数,且参数较少,可以直接用 + 的符号来定义运算符。
    例如:

    MyObject operator+(const MyObject& a) {    return new MyObject(a.getValue());}

调用重载运算符的方式与普通运算符相同,但要明确表达我们是调用用户定义的重载版本:

例如:

int data1 = 5;  int data2 = 7;  int sum = data1 + data2; // 调用默认的整数加法运算符  int sum = operator+(data1, data2); // �amakely 调用自定义重载的加法运算符

是否是成员函数

判断一个运算符是否是成员函数,可以通过以下规则:

  • 赋值运算符 (=)下标运算符 [...]函数调用运算符 ()成员访问运算符 (->) 必须是成员函数。
  • 类似 = 的复合赋值运算符(例如 +=, -= 等)通常也应该定义为成员函数。
  • 一些具有对称性的运算符(如算术运算和比较运算符)通常是非成员函数,例如:
    bool operator==(const MyObject& a, const MyObject& b);

    这种运算符不需要是成员函数。

因此,在定义运算符时,要根据具体需求决定是否将其定义为成员函数。

常用运算符可以被重载的示例

可选运算符 不能重载的运算符
+, -, *, /, %, ^ ::, .*, ., ? :
&, ,, ~, !, =, ,= ,, ~, !, -
<, >, <=, >=, ++, --
<<, >>, ==, !=, &&, ||
+=, -=',/=,%=,^=,&=,*=`
[] (下标运算符)
-> (成员访问运算符), -, new, delete
括号 (), 和逗号 ,

注意:某些特殊运算符不允许重载,例如 ::(标量的成员访问)、.*(指向成员的指针下标)、? :(选择表达式中的 :)。

输入和输出运算符的特殊性

输入和输出运算符有一些特别的规则:

  • 输出运算符 (<<)

    输出运算符通常是非成员函数,定义方式通常是:

    std::ostream& operator<<(const MyObject& obj) {    obj.print();    return std::cout;}
  • 输入运算符 (>>)

    输入运算符则要求更加谨慎,因为它们需要处理可能的失败情况。
    例如:

    MyObject operator>>(std::istream& is, MyObject& obj) {    is >> obj.value;    return obj;}

输入运算符的第一个参数通常是输入流的引用,第二个参数是目标对象的非常量引用。

算术和关系运算符

在定义算术和关系运算符时,需要注意以下几点:

  • 传递性和结合律:确保运算符的传递性和与内置运算符相同的结合律。
  • 复合赋值运算符的优先选择:如果类同时需要定义算术运算符和复合赋值运算符(如 +=),通常应优先使用复合赋值运算符,因为它比直接赋值更灵活。

相等运算符的重要性

如果类包含相等性(==),则通常也需要定义不等式运算符(!=),反之亦然。确保相等运算符具有传递性,避免循环依赖。

递增和递减运算符

递增和递减运算符通常是成员函数,定义方式如下:

  • 前置递增运算符:

    MyObject& operator++() {    this->counter++;    return *this;}
  • 后置递增运算符:

    由于与内置运算符保持一致,后置运算符需要接受一个额外的 int 形参(通常不使用):

    MyObject operator++(int) {    // 这里通常无需改变逻辑,建议保持可选性。    return *this;}

同样,递减运算符 (--) 的定义方式与递增类似。

成员访问运算符

成员访问运算符通常被定义为成员函数。例如:

  • 解引用运算符 ->

    MyObject* operator->() {    return *this;}
  • 箭头运算符 -&> 常用于subtotal 类:

    MyObject operator->(const MyObject& rhs) {    return *this / rhs;}

解引用和乘法运算符的区别在于,解引用是一个一元运算符,而乘法是一个二元运算符。

函数调用运算符

函数调用运算符可以像普通函数一样调用,具有类功能:

  • 定义函数调用运算符的方式:

    void operator()() {    doSomething();}
  • 好处是可以将对象当作函数处理。

如果类同时定义多个版本的调用运算符,其参数类型或数量应有所不同,以避免歧义。

标准库的函数对象

C++ 提供了一些标准库定义的函数对象,这些可以用来简化算法编写。例如:

  • 算术函数对象

    std::plus
    plus;int result = std::accumulate(std::begin(list), std::end(list), 0, plus);
  • 关系函数对象

    std::greater
    greater;if (std::every_of(greater, begin(list), end(list))) { // 做一些判断}

这些函数对象可以用来处理自定义类中的算术和关系运算。

类型转换运算符

类型转换运算符是成员函数,其名称为 operator type()。它们用于将类的对象转换为目标类型,通常取名为 toType 或者 `type().

性能和错误处理

在实现运算符时,需要注意性能和错误处理:

  • 避免在重载运算符中使用 this,除非必要。
  • 处理可能的运算失败,如输入运算符中缺少数据等。

通过遵循这些规则,我们可以创建一个更加灵活和可靠的类框架。

总结

重载运算符是C++强大功能的体现,它允许我们为类定义一系列自定义的运算符行为。通过理解和遵循上述规则,我们可以更好地利用重载运算符,避免潜在的问题,从而提高代码质量和可维护性。

转载地址:http://yptqz.baihongyu.com/

你可能感兴趣的文章
mysql5.6 TIME,DATETIME,TIMESTAMP
查看>>
mysql5.6.21重置数据库的root密码
查看>>
Mysql5.6主从复制-基于binlog
查看>>
MySQL5.6忘记root密码(win平台)
查看>>
MySQL5.6的Linux安装shell脚本之二进制安装(一)
查看>>
MySQL5.6的zip包安装教程
查看>>
mysql5.7 for windows_MySQL 5.7 for Windows 解压缩版配置安装
查看>>
Webpack 基本环境搭建
查看>>
mysql5.7 安装版 表不能输入汉字解决方案
查看>>
MySQL5.7.18主从复制搭建(一主一从)
查看>>
MySQL5.7.19-win64安装启动
查看>>
mysql5.7.19安装图解_mysql5.7.19 winx64解压缩版安装配置教程
查看>>
MySQL5.7.37windows解压版的安装使用
查看>>
mysql5.7免费下载地址
查看>>
mysql5.7命令总结
查看>>
mysql5.7安装
查看>>
mysql5.7性能调优my.ini
查看>>
MySQL5.7新增Performance Schema表
查看>>
Mysql5.7深入学习 1.MySQL 5.7 中的新增功能
查看>>
Webpack 之 basic chunk graph
查看>>