所謂多型性是指發出同樣的訊息被不同型別的物件接收時導致完全不同的行為。這裡所說的訊息主要是指對類的成員函式的呼叫,而不同的行為是指不同的實現。利用多型性,使用者只需傳送一般形式的訊息,而將所有的實現留給接收訊息的物件。物件根據所接收到的訊息而做出相應的動作(即操作)。
函式過載和運算子過載是簡單一類多型性。
所謂函式過載簡單地說就是賦給同乙個函式名多個含義。具體地講,c++中允許在相同的作用域內以相同的名字定義幾個不同實現的函式,可以是成員函式,也可以是非成員函式。但是,定義這種過載函式時要求函式的引數或者至少有乙個型別不同,或者個數不同。而對於返回值的型別沒有要求,可以相同,也可以不同。那種引數個數和型別都相同,僅僅返回值不同的過載函式是非法的。因為編譯程式在選擇相同名字的過載函式時僅考慮函式表,這就是說要靠函式的參數列中,引數個數或引數型別的差異進行選擇。 由此可以看出,過載函式的意義在於它可以用相同的名字訪問一組相互關聯的函式,由編譯程式來進行選擇,因而這將有助於解決程式複雜性問題。如:在定義類時,建構函式過載給初始化帶來了多種方式,為使用者提供更大的靈活性
運算子過載是對已有的運算子賦予多重含義,使同乙個運算子作用於不同型別的資料導致不同型別的行為。運算子過載的實質就是函式過載。在實現過程中,首先把指定的運算表示式轉化為對運算子函式的呼叫,運算物件轉化為運算子函式的實參,然後根據實參的型別來確定需要呼叫的函式,這個過程是在編譯過程中完成的。
一、運算子過載的作用
運算子過載為類的使用者提供了更直觀的介面,使類型別的物件也可以像普通變數一樣進行運算子的表示式運算。運算子過載允許c/c++的運算子在使用者定義型別(類)上擁有乙個使用者定義的意義。
二、運算子過載的規則
(1)c++中的運算子除了少數幾個以外,全部可以過載,而且只能過載已有的運算子。
可以過載的運算子有:
算術運算子:+,-,*,/,%,++,--;
位操作運算子:&,|,~,^,<<,>>
邏輯運算子:!,&&,||;
比較運算子:<,>,>=,<=,==,!=;
賦值運算子:=,+=,-=,*=,/=,%=,&=,|=,^=,<<=,>>=;
其他運算子:,(),->,,(逗號運算子),new,delete,new,delete,->*。
不能過載的運算子只有5個:
類屬關係運算子「.」,成員指標運算子「*」,作用域分辨符「::」,sizeof運算子和三目運算子「?:」。
(2)過載之後運算子的優先順序和結合性都不變。
(3)四個「不能改變」
·不能改變運算子運算元的個數;
·不能改變運算子原有的優先順序;
·不能改變運算子原有的結合性;
·不能改變運算子原有的語法結構。
(4)至少要有乙個操作物件是自定義型別。
(5)過載的運算子含義必須清楚,不能有二義性。
三、運算子過載的2種方法
(1)運算子過載為成員函式
a)對於雙目運算子op,如果要過載op為某類的成員函式,使之能夠實現表示式 k op t,其中k為a類的物件,則應當把op過載為a類的成員函式,該函式只有乙個形參,形參的型別是t所屬的型別。經過這樣過載之後,表示式 k op t 就相當於函式呼叫k.operator op( t )
b)對於前置單目運算子u(如負號「-」),若要過載u為類的成員函式,用來實現表示式
u oprd,其中oprd為a類的物件,則u應當過載為a類的成員函式,且該函式不帶形參。經過過載之後,表示式u oprd 就相當於函式呼叫oprd.operator u()。
c)後置運算子「++」和「--」,若要將它們過載為類的成員函式,用來實現表示式oprd++或oprd--,其中oprd為a類的物件,那麼就應當過載這2個運算子為a類的成員函式,這時函式要帶有乙個整型(int)形參。過載之後,表示式 oprd ++ 和 oprd -- 就分別相當於函式呼叫oprd.operator ++(0) 和 oprd.operator --(0)。
(2)運算子過載為友元函式
a)對於雙目運算子op,如果它的乙個運算元為類a的物件,就可以將op過載為a類的友元函式,該函式有兩個形參,其中乙個形參的型別是a類。經過這樣的過載之後,表示式k op t就相當於函式呼叫operator op( k, t )
b)對於前置單目運算子u(如負號「-」),若要實現表示式 u oprd 其中oprd為a類的物件,則u可以過載為a類的友元函式,函式的形參為a類的物件oprd。經過過載之後,表示式
u oprd 就相當於函式呼叫operator u( oprd )
c)對於後置運算子「++」和「--」,如果要實現表示式 oprd ++ 或 oprd --, 其中oprd為a類的物件,那麼運算子就可以過載為a類的友元函式,這時函式的形參有兩個,乙個是a類的物件oprd,另乙個是整型(int)形參。第二個引數是用於與前置運算子函式相區別的。過載之後,表示式oprd ++ 和 oprd -- 就分別相當於函式呼叫operator ++ (oprd, 0)
和operator -- (oprd, 0)。
(3)兩種過載方法的比較
一般說來,單目運算子最好被過載為成員;對雙目運算子最好被過載為友元函式,雙目運算子過載為友元函式比重載為成員函式更方便,但是,有的雙目運算子還是過載為成員函式為好,例如,賦值運算子。因為,它如果被過載為友元函式,將會出現與賦值語義不一致的地方。
四、特殊運算子的過載
1).下標運算子過載
由於c語言的陣列中並沒有儲存其大小,因此,不能對陣列元素進行訪問範圍的檢查,無法保證給陣列動態賦值不會越界。利用c++的類可以定義一種更安全、功能強的陣列型別。為此,為該類定義過載運算子。
下面先看看乙個例子:
#include <iostream.h>
class chararray //陣列類
~chararray()
int getlength()
char & operator (int i);
private:
int length;
char * buff; };
char & chararray::operator (int i)
else
} void main()
cout<<"\n";
for(cnt=0; cnt<8; cnt++)
cout<<"\n";
cout<<string1.getlength()<<endl; }
該陣列類的優點如下:
(1) 其大小不必是乙個常量。
(2) 執行時動態指定大小可以不用運算子new和delete。
(3) 當使用該類陣列作函式引數時,不必分別傳遞陣列變數本身及其大小,因為該物件中已經儲存大小。
在過載下標運算子函式時應該注意:
(1) 該函式只能帶乙個引數,不可帶多個引數。
(2) 不得過載為友元函式,必須是非static類的成員函式。
2). 過載增1減1運算子
增1減1運算子是單目運算子。它們又有字首和字尾運算兩種。為了區分這兩種運算,將字尾運算視為雙目運算子。表示式
obj++或obj--
被看作為:
obj++0或obj--0
下面舉一例子說明過載增1減1運算子的應用。
#include <iostream.h>
class counter
counter operator ++();
counter operator ++(int );
void print()
private:
unsigned v; };
counter counter::operator ++()
counter counter::operator ++(int)
void main()
c.print();
for(i=0; i<8; i++)
c.print(); }
3). 過載函式呼叫運算子
可以將函式呼叫運算子()看成是下標運算的擴充套件。函式呼叫運算子可以帶0個至多個引數。下面通過乙個例項來熟悉函式呼叫運算子的過載。
#include <iostream.h>
class f ;
double f::operator ()(double x, double y) const
void main()
要注意的是:對於賦值操作符的過載,要解除a的記憶體分配,再製作a的副本。但解除a的記憶體分配後,就沒有可供複製的了,實現**應確定等號左邊的呼叫物件是否與等號右邊的物件向同,測試這個特例,賦值運算子應是防故障的。
**:
C 運算子過載 過載特殊運算子
賦值運算子用於同類物件間的相互賦值。賦值運算子只能被過載為類的非靜態成員函式,不能過載為友元函式和普通函式。對於使用者自定義的類而言,如果沒有過載賦值運算子,那麼c 編譯器會為該類提供乙個預設的過載賦值運算子成員函式。預設賦值運算子的工作方式是按位對拷,將等到右邊物件的非靜態成員拷貝給等號左邊的物件...
C 運算子過載賦值運算子
自定義類的賦值運算子過載函式的作用與內建賦值運算子的作用類似,但是要要注意的是,它與拷貝建構函式與析構函式一樣,要注意深拷貝淺拷貝的問題,在沒有深拷貝淺拷貝的情況下,如果沒有指定預設的賦值運算子過載函式,那麼系統將會自動提供乙個賦值運算子過載函式。賦值運算子過載函式的定義與其它運算子過載函式的定義是...
C 運算子過載轉換運算子
為什麼需要轉換運算子?大家知道對於內建型別的資料我們可以通過強制轉換符的使用來轉換資料,例如 int 2.1f 自定義類也是型別,那麼自定義類的物件在很多情況下也需要支援此操作,c 提供了轉換運算子過載函式 它使得自定義類物件的強轉換成為可能。轉換運算子的生命方式比較特別,方法如下 operator...