多載 Overloading 講師 : 洪安 1
多型 編譯時期多型 ( 靜態多型 ) function overloading 函數多載 如何正確呼叫同名的函數? 利用參數個數與型態 operator overloading 運算子多載 其實同 function overloading 執行時期多型 ( 或動態多型 ) 如何正確呼叫不同物件的相同名稱的成員函數 利用繼承與多型 2
函數多載 Function Overloading 同樣名稱的函數有多種格式, 或說多個函數共用一個函數名稱 可以定義兩個有相同名稱的函數, 但函數簽名 (Signature) 必須不同 引數串列的引數數目 引數型態 預設引數是可以使用不同數目的引數呼叫同一個函數 Animal::Animal(int a, const char * cat = Elephant ){ age = a; strcpy(category,cat); 一個函數定義 兩種不同引數呼叫 Animal ob1(16); 3 Animal ob2(18, Dog );
範例練習 定義一組 print() 函數, 其原型如下 : 當使用 print() 函數時, 編譯程式從函數原型找一個符合函數呼叫的相同簽名 試試 3_Print.cpp, 看看每個呼叫各是執行了哪一個函數! 4
運算子多載的基礎 什麼是運算子多載? 讓運算子 ( 符號 ) 有不同的意義 例 : 運算子的預設意義 ( 以 + 與 = 為例 ) class frac { ; int main() { int x=5, y =3, z ; z = x + y ; // 使用 = + int a[10], b[10], c[10]; c = a + b ; // 可乎??? frac f1(3,5), f2(2, 5), f3 ; f3 = f1 + f2 ; // 3/5 + 2/5 = 1, 可乎? return 0; 可以重新定義 + = 運算子應用在 frac 物件上的意義嗎? 5
如果沒有運算子多載能力 int main() { frac f1(3,5), f2(2, 5), f3 ; f3.set(f1.add(f2)) ; // 模擬 f3 = f1 + f2 ; if (f1.great_equal(f2)) cout << f1 >= f2 ; // f1 >= f2 cout<< f3= ; f3.print() ; // cout << f3= <<f3 ; return 0; 可行嗎? 缺點? f3=f1+f2; if (f1>=f2) { cout << f3; 6
運算子的種類 依運算元分 二元運算子 +, -, *, /, =, >, <, 一元運算子 a++, --b, -c, +d 其他運算子 依功能分 算術運算子 +, -, *, /, =, +=, - =, 比較運算子 >, <, >=, <=, 位元運算子 <<, >>, ~,, ^, 其他運算子 7
算術運算子 8
比較運算子 9
其他運算子 10
多載二元運算子 範例一 class Coord { int x, y ; ; int main() { Coord o1(10,10), o2(5,3), o3 ; o3 = o1 + o2; // o3 (15, 13) o3.print() ; //later, you can use cout << o3 ; return 0; 11
多載運算子 + = (1/4) class Coord { int x, y ; ; int main() { Coord o1(10,10), o2(5,3), o3 ; o3.set(o1.add(o2)); // o3 = o1 + o2 ; o3.print() ; //later, you can use cout << o3 ; return 0; 12
多載運算子 + = (2/4) class Coord { int x, int y; public: Coord(){ Coord(int a, int b){x=a; y=b; Coord add(coord c) { Coord temp ; temp.x = x + c.x ; temp.y = y + c.y ; return temp ; void set(coord c) { x = c.x; y=c.y; ; void print(){cout<<x<<y<<endl; o3.set(o1.add(o2)) ; temp <= o1.add(o2) ; o3 <= temp ; 13
課堂練習 尚未多載 :3_NotYet.cpp #include <iostream> using namespace std; class Coord { int x,y; public: Coord(); Coord(int, int); void print(); ; Coord::Coord(int a,int b) { x=a; y=b; 14
void main() { 多載運算子 + = (3/4) class Coord { Coord operator+(coord c) { // 原 add() Coord temp ; temp.x = x + c.x ; temp.y = y + c.y ; return temp ; void operator=(coord c) { // 原 set() x = c.x; y=c.y; ; Coord o1(10,10), o2(5,3), o3 ; // 原 o3.set(o1.add(o2)); o3.operator=(o1.operator+(o2)); 15
void main() { 多載運算子 + = (4/4) class Coord { o3 = o1 + o2 ; Coord operator+(coord c) { // 原 add() coord temp ; temp.x = x + c.x ; temp.y = y + c.y ; return temp ; void operator=(coord c) { // 原 set() x = c.x; y=c.y; ; Coord o1(10,10), o2(5,3), o3 ; // 原 o3.set(o1.add(o2)); // o3.operator=(o1.operator+(o2); 16
牢記運算式的真面目 o3 = o1 + o2 ; o3 = o1.operator+(o2) ; o3.operator=(o1.operator+(o2)) ; 17
如何多載運算子 在類別中建立運算子函數 (operator function) 語法 class 類別名稱 { // overload 運算子 X 回傳型態 operatorx( 參數列表 ) { ; 18
將多載運算子定義在 class 外 class Coord { Coord operator+(coord c) ; void operator=(coord c) ; ; Coord Coord::operator+(Coord c) {. void Coord::operator=(Coord c) { 19
課堂練習 運算子多載 (3_OpOverload.cpp) int main() { Coord o1(10,10), o2(5,3), o3 ; o3=o1+o2; // o3 = o1 + o2 ; o3.print() ; //later, you can use cout << o3 ; system("pause"); return 0; 20
Call by reference class Coord { 優點? Coord operator+(const Coord& c) ; void operator=(const Coord& c) ; ; Coord Coord::operator+(const Coord& c) { void Coord::operator=(const Coord& c) { 因為 operator+ 傳回 temp, 接著 operator= 以參考接收, 所以第二個 Coord c 必須要加上 const, 以防止修改到原本應已消滅的物件空間之值 21
課堂練習 Call by reference (3_reference.cpp) 將運算子函數的傳入引數改為 reference int main() { Coord o1(10,10), o2(5,3), o3; o3=o1+o2; // o3 = o1 + o2 ; o3.print(); //later, you can use cout << o3 ; system("pause"); return 0; 22
連加與連等 o4 = o1+o2+o3; o4.operator=(o1+o2+o3); o4.operator=(o1.operator+(o2+o3)); o4.operator=(o1.operator+(o2.operator+(o3))); o1=o2=o3; o1.operator=(o2=o3); o1.operator=(o2.operator=(o3)); 23
連加與連等 Coord operator+(coord c) { // 原 add() Coord temp ; temp.x = x + c.x ; temp.y = y + c.y ; return temp ; o1.operator+(o2+o3); void operator=(coord c) { // 原 set() x = c.x; y=c.y; 24 Coord Coord::operator=(Coord c) { x = c.x; y=c.y; return *this; o1.operator=(o2=o3);
課堂練習 連等連加 (3_ContAdd.cpp) int main() { Coord o1(10,10), o2(5,3), o3(3,2),o4,o5 ; o5=o4=o1+o2+o3; // o3 = o1 + o2 ; o5.print() ; //later, you can use cout << o3 ; system("pause"); return 0; 25
多載邏輯與關係運算子 二元運算子 (Binary Operators) 算術運算 : +, -, *, /, =, +=, -=,., 關係運算 : >, <, >=, <=, == 邏輯運算 : &&,, &,, ^ 26
範例 (1/2) class Coord { int x, y ; Q: o1==o2 的真面目? public: Coord() {x = 0 ; y=0 ; Coord(int i, int j) { x=i; y=j; bool operator==(const Coord& ob2) ; ; int main() { Coord o1(10,10); o2(5,3) ; if (o1 == o2) cout << o1 == o2 <<endl ; return 0; 27
範例 (2/2) bool Coord::operator==(const Coord& ob2) { return (this->x==ob2.x) && (this->y==ob2.y); 28
課堂練習 == 多載 (3_Logic.cpp) int main() { Coord o1(10,10), o2(3,5), o3; if (o1==o2) cout<<"o1==o2"<<endl; else cout<<"o1!=o2"<<endl; system("pause"); return 0; 29
多載一元運算子 一元運算子 ++, --, +, - 需求 int main() { Coord o1(10, 10), o2 ; o2 = ++o1 ; o1.print() ; o2 = o1++ ; o1.print() ; return 0; o1.operator++() // 前置 ++, prefix // 後置 ++, postfix 30
如何分辨 prefix 與 postfix ++ class Coord { int x, int y; public: Coord(){ Coord(int a, int b){x=a; y=b; Coord& operator++() { // prefix ++ ++o1 ; x++; y++ ; return *this; 僅用來區別 ++ 或 -- 在後面, 參數值沒有特殊意義 Coord operator++(int) {//postfix ++ Coord temp = *this ; x++; y++ ; return temp ; o1++ ; Q: 為何不寫 void operator++()? 31
Operator ++ 的真面目 ++d1 d1.operator++() Date &operator++() d1++ d1.operator++(0) Date operator++(int) 32
課堂練習 ++ (3_AddAdd.cpp) int main() { Coord o1(10,10),o2; cout<<"o1="; o1.print(); 33 cout<<"o2=o1++"<<endl; o2=o1++; cout<<"o2="; o2.print(); cout<<"o1="; o1.print();... return 0;
使用夥伴運算子函數 源起 o3 = o1+o2 ; o3 = o1.operator+(o2) ; o3 = o1+5 ; o3 = o1.operator+(5) ; o3 = 10 + o2 ; o3 = 10.operator+(o2);????? 使用夥伴函數來定義運算子! 34
夥伴運算子函數 #include<iostream.h> class Coord { int x, y ; ; Coord operator+(coord ob1, Coord ob2) { return Coord(ob1.x+ob2.x, ob1.y+ob2.y) ; void main() { Coord o1(10,10), o2(5, 3), o3; o3 = o1 + o2 ; 參考 operator+(coord, Coord) Q1: 是否為 class Coord 的成員? Q2: 可否取用 x, y? friend Coord operator+(coord ob1, Coord ob2) ; 35 // o3 = operator+(o1, o2) ;
36 10+o2 的解決 class Coord{ int x, y ; public: Coord(){x=0;y=0; Coord(int a){x=a;y=a; Coord(int a, int b){x=a;y=b; friend Coord operator+(coord ob1, Coord ob2); void print(){cout<<x<<y<<endl; ; Coord operator+(coord ob1, Coord ob2) { return Coord(ob1.x+ob2.x, ob1.y+ob2.y) ; int main() { Coord o1(10,10), o2(5, 3), o3; o3 = 10 + o2 ; // It s OK, why? return 0; 實際練習看看!
注意 operator+() 只接收 1 或 2 個參數 1 個參數 : 成員函數 2 個參數 : 一般函數 37
多載 << 與 >> 運算子 << 與 >> 運算子 可供內建資料型態使用 可供使用者自訂類別多載使用 多載 << 運算子 左邊的運算元必須是型態 ostream& 例如 : cout<< ob1 多載 >> 運算子 左邊的運算元必須是型態 istream& 例如 : cin >> ob1 多載這兩個運算子必須使用非成員函式 38
多載 << 運算子範例 函數原型 寫在自訂類別定義中!!! friend ostream &operator<<( ostream&, const PhoneNumber& ); 39 函數定義 ostream &operator<<( ostream& output, const PhoneNumber &num ) { output << ( << num.areacode <<") " << num.exchange << "-" << num.line; return output; // enables cout<< a << b << c; // end function operator<< 函數呼叫 1. operator<<( cout, phone ); 2. cout << phone; // 輸出一個電話號碼
課堂練習 修改 3_OutputOverloading.cpp 中的 print() 成員函數 void Coord::print() { cout<<"("<<x<<","<<y<<")"<<endl; 改為多載 << 運算子 o3.print(); cout << o3 << endl; 40