C++回炉之_C++PrimerPlus_第十一章 使用类

运算符重载

  • 运算符重载是多态的一种形式
  • C++允许赋予运算符多种含义
  • 运算符重载可使使用自定义类型看起来更像基本的数据类型
  • 一个例子

    • 使用 operator声明重载函数
    • 调用 z = x + y; 相当于 z = x.operator+(y);
    
    #pragma once
    
    
    class Point{
    private:
        double m_x;
        double m_y;
    
    protected:
    
    public:
        Point();
        Point(double x, double y);
        ~Point();
    
        void set_x(int x) { m_x = x; }
        double get_x() const { return m_x; }
    
        void set_y(int y) { m_y = y; }
        double get_y() const { return m_y; }
    
        Point operator+(const Point& b) const {
            Point r(m_x + b.m_x, m_y + b.m_y);
            return r;
        } // 重载+运算符
    
    };
    
    
    int main() {
    
        Point x(1, 2), y(3, 4);
        Point z = x + y;
        cout << z.get_x() << " " << z.get_y() << endl;
    
        return 0;
    }
  • 重载限制
    • 重载后的运算符必须至少一个操作数是用户定义的类型
    • 使用运算符重载不能违反运算符原来的句法规则 – 操作数的个数 和 优先级
    • 不能创建新运算符
    • 有些运算符不能重载 – 可百度一下
    • 有些运算符只能通过成员函数重载 – 而不能通过非成员函数重载
      • = () [] ->
  • 另一种重载 – 非同类型重载

    Point operator*(double v) const {
    Point r(m_x*v, m_y*v);
       return r;
    }
    Point x(1, 2);
    Point z = x*2.0;

友元函数

  • 重载遗留的问题

    • 上面的语句 z = x*2.0; 会转换成 z = x.operator*(2.0);
    • 但是若语句为 z = 2.0*x; 呢, 要想达到与上式一样的效果,可以

      • 使用非成员函数

        Point operator*(double a, const Point& b);
        • 问题是必须给Point提供可以访问私有成员的公有方法
      • 使用友元函数 – 下面介绍
  • 友元函数

    • 可以访问类的私有成员
    • 是一类特殊的非成员函数
    • 声明

      • 原型放在类中 – 但不是类成员函数 – 不用使用::
      • 前加friend关键字 – 声明中加, 定义中不加 – 可访问类的私有成员

        friend Point operator*(double a, const Point& b);
    • 定义
      • 不用加friend关键字
      • 也不用加 类名:: 限定符
      • z = 2.5*a; 会转化为 z = operator*(2.5, a); – 非成员函数
    • 选择
      • 友元重载和成员函数重载只可选择一种
      • 有时候只能用友元 – 第一个参数不能是类对象时
      • 有时候友元重载会更好
    • 一种常用的友元函数 – 重载<<运算符

      friend ostream& operator<<(ostream& out, const Point& a);
    • 改进后的Point类

      
      #pragma once
      
      
      #include 
      
      using std::ostream;
      
      class Point{
      private:
          double m_x;
          double m_y;
      
      protected:
      
      public:
          Point();
          Point(double x, double y);
          ~Point();
      
          void set_x(int x) { m_x = x; }
          double get_x() const { return m_x; }
      
          void set_y(int y) { m_y = y; }
          double get_y() const{ return m_y; }
      
          Point operator+(const Point& b) const;
          Point operator*(double v) const;
          friend Point operator*(double a, const Point& b);
      
          friend ostream& operator<<(ostream& out, const Point& a);
      
      
      };
      
      
      #include "Point.h"
      
      
      #include 
      
      using std::cout;
      using std::endl;
      
      Point::Point() {
          m_x = 0.0;
          m_y = 0.0;
      }
      
      Point::Point(double x, double y) {
          m_x = x;
          m_y = y;
      }
      
      Point::~Point() {
          cout << "point " << m_x << " " << m_y << "is deleted\n";
      }
      
      Point Point::operator+(const Point& b) const {
          Point r(m_x + b.m_x, m_y + b.m_y);
          return r;
      }
      
      Point Point::operator*(double v) const {
          Point r(m_x*v, m_y*v);
          return r;
      }
      Point operator*(double a, const Point& b){
          Point r(a*b.m_x, a*b.m_y);
          return r;
      }
      
      ostream& operator<<(ostream& out, const Point& a) {
          out << a.m_x << " " << a.m_y;
          return out;
      }
      
      
      #include 
      
      
      #include "Point.h"
      
      using namespace std;
      
      int main() {
      
          Point x(1, 2), y(3, 4);
          Point z = x + y;
          cout << z << endl;
      
          Point zz = 2.0*x;
          cout << zz << endl;
      
          cout << z << endl << zz << endl;
          return 0;
      
      }
      

类的转换 – 转换函数

  • 其他类型转换到类

    • 只含有一个参数的构造函数可以作为转换函数,进行自动(隐式)转换

      Point(double v) { m_x = m_y = v; }  // Point类的一个构造函数
      Point t = 12.0;                     // 自动转换 -- 相当于 Point obj = Point(12.0);
    • 有时候并不需要上述自动转换 – 在函数原型(定义中不需要)前添加explicit关键字即可

      explicit Point(double v);
      • 但是仍然可以使用显示转换
      Point t = Point(12.0);` 或 `Point t = (Point)12.0; // 旧式
    • 当定义了 Point(double); 之后,z = 12.0 + x; 即使不使用友元函数也可运行
      • 因为12.0会隐式地转换为Point类型
  • 类转换到其他类型 – 转换函数

    • 声明

      operator type_name();
      operator double();
      • 必须是类方法
      • 不能指定返回类型
      • 不能有参数
    • 使用

      operator double() const; // Point的一个成员函数
      Point::operator double() const { return m_x + m_y; } // 定义
      Point t; double v = t; // 隐式
      double v = double(t);  // 显式
      • 注意不要存在二义性
      • C++11之后, explicit 也可用于转换函数,以防止隐式转换

        explicit operator double() const;
        double v = t;           // 如果加了explicit, 则此句会报错

你可能感兴趣的:(C/C++)