1. 程式人生 > >C++回爐之_C++PrimerPlus_第十一章 使用類

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 <iostream>
      
      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 <iostream>
      
      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 <iostream>
      
      
      #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, 則此句會報錯