1. 程式人生 > >c++中的多型機制——運算子過載

c++中的多型機制——運算子過載

一:c++中的多型機制一般至少有四種實現方式:

1: 普通函式過載,引數型別不同(引數列表不同),返回值型別可以相同

2: 運算子過載:一般用於對我們自定義的類中的資料進行操作

3: virtual虛擬函式,一般是在類的繼承中實現的。

4:使用模板:實現類的多型

二:c++過載機制:

函式返回型別不影響生成的符號名

函式名,引數列表(引數型別、數目)才是影響符號名的因數

例如:foo_int_int這樣的名字包含了函式名、函式引數數量及型別資訊,C++就是靠這種機制來實現函式過載的。例如,在C++中,函式void foo( int x, int y )與void foo( int x, float y )編譯生成的符號是不相同的,前者為_foo,

後者為_foo_int_float

為什麼要對運算子進行過載:

三:為什麼要對運算子進行過載

        C++預定義中的運算子的操作物件只侷限於基本的內建資料型別,但是對於我們自定義的型別(類)是沒有辦法操作的。但是大多時候我們需要對我們自定義的型別進行類似操作,這個時候就需要我們對這麼運算子進行重新定義,賦予其新的功能,以滿足自身的需求。

過載運算子的兩種形式:
過載運算子有兩種方式,即:

過載為類的成員函式||過載為類的非成員函式。

過載為類的非成員函式的時候:

通常我們都將其宣告為友元函式,因為大多數時候過載運算子要訪問類的私有資料,(當然也可以設定為非友元非類的成員函式。但是非友元又不是類的成員函式是沒有辦法直接訪問類的私有資料的),如果不宣告為類的友元函式,而是通過在此函式中呼叫類的公有函式來訪問私有資料會降低效能。所以一般都會設定為類的友元函式

,這樣我們就可以在此非成員函式中訪問類中的資料了。

四:一個簡單的時間類

MyTime.h

#pragma once
#ifndef MYTIME_H_
#define MYTIME_H_
class CMyTime
{
private:
int m_hours;
int m_minutes;
public:
CMyTime();
CMyTime(int h, int m = 0);
void AddHr(int h);  //小時更改
void AddMin(int m);//分鐘更改
void Reset(int h = 0, int m = 0);  //重新設定時間
CMyTime operator+(const CMyTime &t) const;  //過載加法
CMyTime operator-(const CMyTime &t) const;  //過載減法
CMyTime operator*(double n) const;                //過載乘法
void Show() const;
~CMyTime();
};
#endif
#include "MyTime.h"
#include <iostream>

CMyTime::CMyTime()
{
m_hours = 0;
m_minutes = 0;
}


CMyTime::CMyTime(int h, int m)
{
m_hours = h;
m_minutes = m;
}


CMyTime::~CMyTime()
{
}


void CMyTime::AddHr(int h)                                             //小時更改
{
m_hours += h;
}


void CMyTime::AddMin(int m)                                             //分鐘更改
{
m_minutes = m;
}


void CMyTime::Reset(int h, int m)                                           //重新設定時間
{
m_hours = h;
m_minutes = m;
}


CMyTime CMyTime::operator+(const CMyTime &t) const              //過載加法運算子函式
{
CMyTime sum;
sum.m_minutes = t.m_minutes + m_minutes;
sum.m_hours = t.m_hours + m_hours + sum.m_minutes / 60;
sum.m_minutes %= 60;
return sum; //返回區域性變數會建立區域性變數的副本,不能返回區域性變數的引用,過載 = 運算子的時候返回的是一個引用,請參考博c++的String類
}


CMyTime CMyTime::operator-(const CMyTime &t) const         //過載為減法運算子函式
{
CMyTime diff;
int tot1, tot2;
tot1 = t.m_minutes + 60 * t.m_hours;
tot2 = m_minutes + 60 * t.m_hours;
diff.m_minutes = (tot2 - tot1) % 60;
diff.m_hours = (tot2 - tot1) / 60;
return diff;
}


CMyTime CMyTime::operator*(double n) const                 //過載為乘法運算子函式。
{
CMyTime result;
long totalMinutes = m_hours * 60 * n+ m_minutes *n;
result.m_minutes = totalMinutes % 60;
result.m_hours = totalMinutes / 60;
return result;
}


void CMyTime::Show() const
{
std::cout << m_hours << " hours "
<< m_minutes << " minutes\n";
}
main.cpp
// Study11-02.cpp : 定義控制檯應用程式的入口點。
//

#include <iostream>
#include "MyTime.h"

int  main( )
{
using std::cout;
using std::endl;
CMyTime weeding(4, 35);
CMyTime waxing(2, 47);
CMyTime total;
CMyTime diff;
CMyTime adjusted;


cout << "weeding Time = ";
weeding.Show();
cout << endl;


cout << "waxing Time = ";
waxing.Show();
cout << endl;


cout << "total work Time = ";   //(1)
total = weeding + waxing;
total.Show();
cout << endl;


diff = weeding - waxing;
cout << "weeding Time - waxing Time = "; //(2)
diff.Show();
cout << endl;


adjusted = total *1.5;                     //(3)
cout << "adjusted work Time = ";
adjusted.Show();
cout << endl;


return 0;
}


五 :過載的兩個版本

接下來我們為了更好的瞭解過載運算子,來進行<<運算子的過載:

現在我們想讓 cout<<adjusted; 這句話能直接執行輸出,(顯然這種輸出方式如果不過載<<運算子是沒有辦法執行的。因為cout根本不知道輸出adjusted的什麼東西),對於<<的過載我們有兩種版本:

第一種宣告為成員函式

照葫蘆畫瓢:CMyTime operator<<(ostream &s); 那麼這種生命方式會造成什麼結果呢?答案是:輸出會變成:adjusted<< cout;或許看起來很不好,但這確實是正確的。因為這等價於:adjusted.operator<<(cout);

第二種版本:(也是更好的版本):MyTIme.h 宣告:friend void operator<<(ostream &os,const CMyTime &t);     MyTime.cpp實現:  void operator<<(ostream &os,const CMyTime &t){os << t.hours << t.minutes};這樣就可以執行cout << adjusted 這條語句了。

那麼最重要的問題來了,我們什麼時候宣告為成員函式,什麼時候宣告為非成員函式呢?

首先,我們要明白這句話:對於成員函式來說,一個運算元通過this指標隱式的傳遞,(即本身),另一個運算元作為函式的引數顯示的傳遞;對於友元函式(非成員函式)兩個運算元都是通過引數來傳遞的。

(1)一般來說,彈幕運算子過載為類的成員函式,雙目運算子過載為類的友元函式(咳咳,一般情況下)

(2)雙目運算子不能將 = 。 ()【】。-> 過載為類的友元函式。

(3)如果運算子的第一次運算元要求為隱式轉換則必須為友元函式。

(4)當最左邊的要求為類物件,而右邊的是一個內建型別,則要為友元函式。