C++ primer 第五版个人笔记 第十四章 重载运算与类型转换

14.1 基本概念

  1. 除了重载的函数调用运算符operator()外,其他重载运算符不能含有默认实参;
  2. 当一个重载的运算符是成员函数时,this绑定到左侧运算对象,成员运算符函数的(显式)参数数量比运算对象少一个;
  3. 对于一个运算符函数来说,它或者是类的成员或者至少含有一个类类型的参数;不能为内置类型的运算对象改变运算符的含义;
  4. 有四个符号(+,-,*,&)既是一元运算符也是二元运算符,都能重载,从参数的数量可以推断到底定义的是那种运算符;
  5. 重载的运算符的优先级和结合律与对应的内置运算符保持一致;
  6. 不能被重载的运算符(::) , (.*), (.), (? :)
  7. 可以使用运算符的直接和间接调用
    data1 + data2 ;
    operator+(data1,data2);  //两种调用方式等价

     

  8. 调用重载的成员运算符函数

    data1 += data2;
    data1.operator+(data2);   //两种调用方式等价

     

  9. 有些函数在C++里有一些特定规定,如|| 和&&的短路属性,因此不建议重载逗号(,)取地址(&)逻辑与(&&)逻辑或(&&);

  10. 确定运算符定义为成员函数还是普通的非成员运算符有一下几个准则;a,赋值(=),下标([]),调用(()),和成员访问箭头(->)运算符必须是成员; b, 符合赋值运算符一般来说应该is成员,但并非必须; c, 改变对象状态的运算符或者与给定类型密切相关的运算符,如递增、递减和解引用运算符,通常应该是成员; d, 具有对称性的运算符可能转换任一一端的运算对象,如算术、相等性、关系和位运算符等,通常应该是普通的非成员函数; 

 14.2 输入和输出运算符

  1. 输出运算符的第一个形参是一个非常量ostream对象的引用,非常量是因为向流写入内容会改变其状态,引用是因为不能直接复制一个ostream对象;
  2. 通常输出运算符应该主要负责打印对象的内容而非控制格式,输出运算符不应该打印换行符;
  3. 为类自定义IO运算符的时候,必须将其定义为非成员函数,并且一般要声明为友元;
  4. 输入运算符必须考虑输入可能失败的情况,而输出运算符不需要,详见495页代码,当读取操作发生错误时,输入运算应该负责从错误中恢复,书例中的办法是赋予一个默认构造的空sales_data对象;

 

14.3 算术和关系运算符

  1. 如果存在唯一一种逻辑可靠的<定义,则应该考虑为这个类定义<运算符;如果类同时还包含==,则当且仅当<的定义和==的结果一致时才定义<运算符;简而言之就是如果存在歧义的<运算符,最好不要定义;

 

14.4 赋值运算符

  1. vector的值初始化实际是重载了 赋值运算符=,参数是一个初始化列表(initializer_list<string> il);
  2. 赋值运算符必须定义为类的成员(因其要返回左侧对象的引用),复合赋值运算符通常情况下也应该这么做;

 

14.5 下标运算符

  1. 如果一个类包含下标运算符,则它通常会定义两个版本,一个返回普通引用,另一个是类的常量成员并且返回常量引用;

 

14.6 递增和递减运算符

  1. 前置和后置运算符唯一的区别是后置版本接受一个额外的(不被使用)int类型的星璀璨,后置运算符返回的是对象的原值,前置返回递增或递减后的对象的引用;
  2. 先定义前置版本运算符,后置版本将调用前置版本来完成实际的工作;
  3. 显示调用递增或递减运算符是需要传值来区分是否是前置还是后置
    p.operator++(); //调用前置++
    p.operator++(0); //调用后置++

     

14.7 成员访问运算符

  1. 重载的箭头运算符必须返回类的指针或者自定义了箭头运算符的某个类的对象,重载箭头运算符的工作原理见505页;

 

14.8 函数调用运算符

  1. 函数调用运算符(()一对括号) 必须是成员函数,一个类可以定义多个不同版本的调用运算符,相互之间应该在参数数量或类型上有所区别;

  2. 如果类定义了调用运算符,则该类的对象称作函数对象,因为可以调用这种对象,所以说这些对象的“行为像函数一样”

  3. 函数对象常常作为泛型算法的实参;例如可以使用标准库for_each算法和自定义的类来组合完成一些功能;

  4. lambda其实可以看作是一个未命名类的未命名对象

  5. 标准库定义的函数对象列表见510页,可以将函数对象应用到泛型算法中,产生更多的用途

  6. 关联容器使用less<T>对元素进行排序,因此不需要直接声明less;

  7. 标准库function类型的用法,详见512页,从此编写计算器程序不用if else了;

 

14.9 重载、类型转换与运算符

  1. 类型转换运算符是类的一种特殊的成员函数,将类类型的值转换成奇台类型,一般形式为  operator type() const; 它不能声明返回类型,形参列表也必须为空,通常是const(因为类型转换运算符通常不应该改变待转换对象的内容);
  2. 避免过度使用类型转换函数,类型转换函数有可能不能达到设计者的意图,通过定义一个或多个普通成员函数来满足设计的需求或获取有用的信息;
  3. 可以通过显示的类型转换运算符来防止一些异常情况的发生,在 operator前面加上 explicit; 加了explicit之后类型转换就成了显式的,不能通过隐式转换其类型,只能通过显示转换(static_cast<type>等),有一种情况例外是当表达式用作条件时,编译器会将显式的类型转换自动应用,即显式的类型转换将被隐式地执行
    while(std::cin>>value) 
    //istream类其实是显式的定义了转换为bool类型,但是在条件语句中
    //编译器隐式地执行显示转换,如下几种情况会进行类似转换
    // if、while 及do 语句的条件部分
    // for语句头的条件表达式(第一个;到第二个;之间)
    // 逻辑非运算符(!)、逻辑或运算符(||)、逻辑与运算符(&&)的运算对象
    // 条件运算符(? :)的条件表达式(?左边)

     

  4. 向bool的类型转换通常用在条件部分,因此operator bool 一般定义成explicit的;
  5. 为了避免二义性,不要为类定义相同的类型转换,也不要在类中定义两个及两个以上转换源或转换目标是算术类型的转换,几个常见用例见518页;
  6. 当我们使用两个用户定义的类型转换时,如果转换函数之前或之后存在标准类型转换,则标准类型转换将决定最佳匹配是哪个(如实参是short,相比于double会优先匹配int);
  7. 进行运算符重载之后,当通过类类型的对象(或该类对象的指针或引用)进行函数调用时,只考虑该类的成员函数;当在表达式中使用重载的运算符时,无法判断正在使用的是成员函数还是非成员函数;
  8. 如果我们对同一个类既提供了转换目标是算术类型的类型转换,也提供了重载的运算符,则将会遇到重载运算符与内置运算符的二义性问题;

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
《C Primer》是一本针对C语言初学者的经典教材,第五版的第六章主要介绍了函数的基本概念和用法。 在第六章中,教材首先介绍了函数的定义和调用。函数是具有独立功能的代码块,可以通过函数名来调用。函数由函数头、参数、函数体和返回值组成。函数头包括函数类型、函数名和参数类型,参数用于接收传递给函数的值,返回值用于将结果返回给调用者。 接着,教材详细介绍了函数的参数传递方式,包括按值传递、按引用传递和按指针传递。按值传递是指将参数的值复制给形参,按引用传递是指将参数的引用传递给形参,而按指针传递是将参数的地址传递给形参。不同的传递方式在函数内部对参数进行操作时,会对应不同的结果。 此外,教材还讲解了函数的返回值和函数的调用顺序。函数的返回值类型由函数头中的类型确定,可以是任意类型。当函数需要返回多个值时,可以使用结构体或指针进行返回。函数的调用顺序决定了函数执行的顺序,即哪个函数先执行,哪个函数后执行。 在函数的实现过程中,教材介绍了函数的定义和声明、局部变量和全局变量、递归等内容。通过这些知识点的学习,读者可以了解到函数的具体细节和一些实践技巧。 总的来说,第五版的第六章通过清晰的语言和丰富的例子,循序渐进地讲解了函数的基本概念和用法。学完这一章,读者将能够理解函数的定义、调用、参数传递、返回值和实现等方面的知识,为之后的学习和实践打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值