C++回爐之_C++PrimerPlus_第十一章 使用類
阿新 • • 發佈:2019-02-16
運算子過載 |
- 運算子過載是多型的一種形式
- 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
- 使用
- 過載限制
- 過載後的運算子必須至少一個運算元是使用者定義的型別
- 使用運算子過載不能違反運算子原來的句法規則 – 運算元的個數 和 優先順序
- 不能建立新運算子
- 有些運算子不能過載 – 可百度一下
- 有些運算子只能通過成員函式過載 – 而不能通過非成員函式過載
= () [] ->
另一種過載 – 非同型別過載
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, 則此句會報錯