首页 C++ Primer Plus-第11章 使用类
文章
取消

C++ Primer Plus-第11章 使用类

11.1 运算符重载

  • C++允许将运算符重载扩展到用户定义的类型
  • 要重载运算符,需要使用被称为运算符函数的特殊函数形式:operatorop(argument-list)operator+()重载+运算符
  • op必须是有效的C++运算符,不能虚构一个新的符号,比如不能是@

11.2 计算时间:一个运算符重载示例

  • 详情见p381,下面记一些重点

  • 函数原型:Time operator+(const Time & t) const

  • 调用时,有两种方式:total = coding.operator+(fixing);total = coding + fixing;

  • 编译器将根据操作数的类型来确定如何做

    1
    2
    3
    
    t4 = t1 + t2 + t3;
    t4 = t1.operator+(t2 + t3);
    t4 = t1.operator+(t2.operator+(t3));
    
  • 运算符重载的限制:

    1. 重载后的运算符必须至少有一个操作数是用户定义的类型,防止用户为标准类型重载运算符

    2. 使用运算符时不能违反运算符原来的句法规则,比如不能将求模运算符(%)重载成使用一个操作数

    3. 不能创建新运算符

    4. 不能重载下面的运算符:

      zSctg0.jpg

    5. 下面的运算符只能通过成员函数重载:

      • =:赋值运算符
      • ():函数调用运算符
      • []:下标运算符
      • ->:通过指针访问类成员的运算符
    6. 可重载的运算符:

      zScyCR.jpg zScr59.jpg

11.3 友元

  • C++提供了另外一种形式的访问权限:友元:

    • 友元函数
    • 友元类
    • 友元成员函数
  • 通过让函数成为类的友元,可以赋予该函数与类的成员函数相同的访问权限,本节仅介绍友元函数

  • 在为类重载二元运算符时(带两个参数的运算符)常常需要友元,比如两个类型不同的参数:A = B*2.75和A = 2.75*B。按理来说应该一样,但第一个参数应该是类对象,所以第二个就会出问题

  • 第一种方式是告知每个人按第一种方式编写,另一种解决方式——非成员函数

  • 大多数运算符都可以通过成员或非成员函数来重载

  • 非成员函数不是由对象调用的,它使用的所有值(包括对象)都是显示参数比如:

    1
    2
    3
    4
    
    A = 2.75 * B;
    A = operator*(2.75, B);
    //函数原型:
    Time operator*(double m , const Time & t);
    
    • 问题就是非成员函数不能访问对象的私有数据,故出现了友元函数
  • 创建友元函数两部曲:

    • 将原型放在类声明中,并加上关键字friendfriend Time operator*(double m , const Time & t);
      • 虽然operator*()函数是在类声明中声明的,但它不是成员函数,所以不能使用成员运算符来调用;
      • 虽然operator*()函数不是成员函数,但它与成员函数的访问权限相同
    • 编写函数定义(因为不是成员函数,所以不要使用Time::限定符),在函数定义时,就不需要写friend关键字了
  • 如果要为类重载运算符,并将非类的项作为其第一个操作数,则可以用友元函数来反转操作数的顺序

  • 通过友元函数重载<<:

    1
    2
    3
    4
    
    ostream & operator<<(ostream & os, const Time & t)
    {
        os<<t.hours<<" hours, "<<t.minutes<<" minutes";
    }
    

11.4 重载运算符:作为成员函数还是非成员函数

  • 一般来说,非成员函数应该是友元函数
  • 在定义运算符时,必须选择一种格式(当两个参数都是同样的时候),因为两种格式都与同一个表达式匹配,同时定义这两种格式将被视为二义性错误

11.5 再谈重载:一个矢量类

  • 这小节是个例子,使用了上面的知识点和以前的一些知识点,比如枚举量啊之类的,详情见p398

11.6 类的自动转换和强制类型转换

  • C++语言不会自动转换不兼容的类型,比如将数字赋给指针变量

  • 当无法自动类型转换时,可以使用强制类型转换,如:

    1
    
    int *p = (int *) 10;
    
  • 可以将类定义成与基本类型或另一个类相关,使得从一种类型转换为另一种类型是有意义的

    • 在C++中,接受一个参数(如果有两个参数,第二个参数提供了默认值的话也行)的构造函数为将类型与该参数相同的值转换成类提供了蓝图:

      1
      
      Stone(double lbs);//构造函数
      

      Stone cat; cat = 19.6;//double转换为Stone类型

      1
      
          
      
  • C++新增了关键字explicit来关闭隐式自动转换这种自动特性,但仍然允许显式强制类型转换:

    1
    
    explicit Stone(double lbs)
    
  • 还有二步转换:比如int先转double再转成Stone;当且仅当不存在二义性时才可以二步转换

  • 转换函数:将类对象转换成数字

    • operator typename();转换为typename类型,比如operator double();

    • 转换函数必须是类方法

    • 转换函数不能指定返回类型

    • 转换函数不能有参数

    • 同样不能使用二义性转换

      1
      2
      3
      4
      
      Stone::operator double() const
      {
          return pounds;//成员变量
      }
      
  • 转换函数和友元函数配合,可以实现数字=类+数字数字=数字+类

本文由作者按照 CC BY 4.0 进行授权

C++ Primer Plus-第10章 对象和类

C++ Primer Plus-第12章 动态内存和类