運算符重載ios
友元函數數組
重載<<運算符,以便於輸出函數
狀態成員學習
使用rand生成隨機值spa
類的自動轉換和強制類型轉換指針
類轉換函數code
本章首先介紹運算符重載,容許標準C++運算符用於類對象->友元,這種機制使得非成員函數能夠訪問私有數據->如何命令C++對類執行自動類型轉換。對象
學習本章和12章將對類構造函數和類析構函數有更深刻的瞭解。作用域
以前介紹了函數重載,運算符重載是一種形式的C++多態。原型
實際上,不少C++運算符已經被重載,好比*地址運算符和乘法,C++根據操做數的數目和類型來決定採用哪一種操做。
能夠定義一個表示數組的類,並重載+運算符。因而:
evening = sam + janet; // add two array objects;
要重載運算符,需遵照運算符函數的格式:
operator op(argument list)
eg:
operator +() operator *()
op必須是有效的C++運算符,不能虛構一個新的符號。
假設有一個Salesperson類,並重載了+運算符,使得兩個對象的銷售額相加:
districts = sid + sara; 至關於: districts = sid.operator+(sara);
而後該函數將隱式地使用sid(由於它調用了方法)而顯式地使用sara對象(由於它被做爲參數傳遞),來計算總和並返回。
2小時35分鐘和2小時40分鐘相加的運算符重載代碼示例,
第7張經過定義結構相加來處理相似的狀況,如今推廣,採用類以及運算符重載來實現:
time.h #ifndef MYTIMED_H_ #define MYTIMED_H_ class Time { private: int hours; int minutes; public: Time(); Time(int h, int m = 0); void AddMin(int m); void AddHr(int h); void Reset(int h = 0, int m = 0); Time Sum(const Time & t) const; void Show() const; }; #endif ================ time.cpp #include<iostream> #include "time.h" Time::Time(){ hours = minutes = 0; } Time::Time(int h, int m) { hours = h; minutes = m; } void Time::Time::AddMin(int m) { // 一、分鐘相加 // 二、分鐘取模,結果爲當前分鐘 // 三、分鐘除法,若結果大於0,小時加1 minutes += m; hours += minutes / 60; minutes = minutes % 60; } void Time::Time::AddHr(int h) { // 一、小時相加 // 二、小時取模,結果爲當前小時 hours += h; hours = hours % 24; } void Time::Reset(int h, int m) { hours = h; minutes = m; } Time Time::Sum(const Time & t) const { Time sum; sum.minutes = minutes + t.minutes; sum.hours = hours + t.hours + sum.minutes/60; sum.minutes = sum.minutes % 60; // hours = hours % 24; return sum; } void Time::Show() const{ using std::cout; using std::endl; cout << "hours: " << hours <<endl; cout << "minutes: " << minutes <<endl; }
然而,返回值不能使引用,由於函數將建立一個新的Time對象。返回對象將建立對象的副本,而調用函數可使用它。
然而,若返回類型爲Time &,因爲sum是局部變量,在函數結束時被刪除,所以引用將指向一個不存在的對象。
使用返回類型Time意味着程序將在刪除sum以前構造它的拷貝,調用函數將獲得該拷貝。
usetime.cpp #include<iostream> #include"time.h" int main() { using namespace std; Time planning; Time coding(2, 20); Time fixing(4, 20); Time sum; cout << "planning: " << endl; planning.Show(); cout << "coding: " << endl; coding.Show(); cout << "fixing: " << endl; fixing.Show(); cout << "sum: " << endl; sum = coding.Sum(fixing); sum.Show(); return 0; }
只需將sum()的名稱改爲operator+()便可。
這樣,能夠像調用Sum()那樣來調用operator+()方法:sum = coding.operator+(fixing);
將該方法命令爲operator+()後,也可使用運算符表示法:sum = coding+fixing;
time.h中
Time operator+(const Time & t) const;
time.cpp中
Time Time::operator+(const Time & t) const {
usetime.cpp中
sum = coding+fixing;
總之,operator+()函數的名稱使得可使用函數表示法或運算符表示法來調用它。
能夠將兩個以上的對象相加嗎?
t4 = t1 + t2 + t3;yes
運算符重載的限制:
至少有一個操做數是用戶定義的類型;
使用運算符時不能違反運算符原來的句法規則;例如,不能將%重載成使用一個操做數;不能修改運算符的優先級;
不能建立新的運算符
不能重載下面的運算符
sizeof:sizeof運算符
.:成員運算符
*:成員指針運算符
:::做用域解析運算符
?::條件運算符
typeid:一個RTTI運算符
const_cast:強制類項轉換運算符
dynamic_cast:強制類項轉換運算符
reintcrpret_cast:強制類項轉換運算符
static_case:強制類項轉換運算符
表11.1中大多數運算符均可以經過成員或非成員函數進行重載,但下面的運算符只能經過成員函數進行重載:
=:賦值運算符
():函數調用運算符
[]:下標運算符
->:經過指針訪問類成員的運算符
表11.1
。。。。。。。。
注意:在重載運算符時遵循一些明智的限制,eg:不能將*運算符重載成交換兩個對象的數據成員。表示法中沒有任何內容能夠代表運算符完成的工做,所以最好定義一個其名稱具備說明性的類方法,egswap();
好比乘法和減法;
time.h Time operator-(const Time & t) const; Time operator*(double a) const; ======================== time.cpp Time Time::operator-(const Time & t) const { Time diff; int tol1; int tol2; tol1 = t.minutes + t.hours * 60; tol2 = minutes + hours * 60; diff.minutes = (tol2 - tol1) % 60; diff.hours = (tol2 - tol1) / 60; return diff; } Time Time::operator*(double a) const { Time aa; int total = hours * 60 * a + minutes * a; aa.minutes = total % 60; aa.hours = total / 60; return aa; } ======================== usetime.cpp cout << "diff: " << endl; diff = coding-fixing; diff.Show(); cout << "result: " << endl; result = coding * 2; result.Show();
公有類方法提供私有部分的惟一訪問途徑,但這種限制太嚴格。
C++提供了另外一種形式的訪問權限:友元。
友元函數;
友元類;
友元成員函數;
經過讓函數成爲類的友元,能夠賦予該函數與類的成員函數相同的訪問權限。只介紹友元函數,其餘兩種15章介紹。
爲什麼須要友元?在爲類重載二元運算符時經常須要友元。
例如,乘法運算符將一個Time值與一個double值結合在一塊兒。這限制了該運算符的使用方式。
A\B爲Time類
A = B * 2.75;//能夠這麼使用,至關於A = B.operator*(2.75);
A = 2.75 * B; //不能夠,由於2.75不是Time類
解決辦法:
1、限制使用方式
2、非成員函數
非成員函數不是由對象調用的,它使用的全部值都是顯示參數。
這樣A = 2.75 * B;
與下面的非成員函數匹配:
A = operator*(2.75, B);
該函數的原型以下:
Time operator*(double m, const Time & t);
對於非成員重載運算符函數來講,運算符表達式左邊的操做數對應於運算符函數的第一個參數,運算符表達式右邊的操做數對應於運算符函數的第二個參數。而原來的成員函數則按相反的順序處理操做數。
使用非成員函數能夠按所需的順序得到操做數,但引起一個新問題:即非成員函數不能直接訪問類的私有數據,至少常規非成員函數不能訪問。然而,有一個特殊的非成員函數能夠訪問類的私有成員,稱爲友元函數
第一步:將其原型放在類聲明中,並加上關鍵字friend
friend Time operator*(double m, const Time & t);
該原型意味着:
雖然operator*()函數是在類聲明中聲明的,但它不是成員函數,所以不能使用成員運算符來調用;
雖然operator*()不是成員函數,但它與成員函數的訪問權限相同。
第二步:編寫函數定義,不要使用Time::限定符,不要在定義中使用關鍵字friend
Time operator*(double m, const Time & t) { Time result; long totalminutes = (t.hours * 60 + t.minutes) * m; result.hours = totalminutes / 60; result.minutest =totalminutes % 60; return result; }
提示:若是要爲類重載運算符,並將非類的項做爲第一個操做數,則能夠用友元函數來反轉操做數的順序。
能夠對<<運算符重載,使之能與cout一塊兒來顯示對象的內容。eg:
cout << time;
實際上,它已經被重載不少次了。
最初,<<是位運算符;
ofstream類對該運算符進行了重載,用做輸出,能識別全部的基本類型;
一、<<的第一種重載版本
要使Time類知道使用cout,必須使用友元函數。由於第一個操做數不是Time。
void operatorMM(ostream & os, const Time & t) { os << t.hours << " hours, " << t.minutes << " minutes"; } cout << time;