10 多載函數 10.1 多載概論 10-2 10.1.1 多載一般函數 10-2 10.1.2 多載成員函數 10-3 10 多載函數 10.1 多載概論 10-2 10.1.1 多載一般函數 10-2 10.1.2 多載成員函數 10-3 10.1.3 多載建立者函數 10-5 10.2 多載運算符號 10-8 10.2.1 多載運算符號限制 10-9 10.2.2 運算符號函數 10-10 10.2.3 多載 >> 運算符號 10-10 10.2.4 多載 << 運算符號 10-13 10.2.5 多載雙運算元符號 10-16 10.2.6 多載單運算元符號 10-20 10.2.7 多載前置運算符號 10-23 10.2.8 多載後置運算符號 10-23 10.3 轉換型態 10-26 10.3.1 基本型態轉基本型態 10-26 10.3.2 基本型態轉類別型態 10-27 10.3.3 類別型態轉基本型態 10-29 10.3.4 類別型態轉類別型態 10-31
10.1 多載概論 多載(overloading)就是重複定義多個相同名稱的函數,但這些函數的功能不完全相同。所以多載函數的情況包括:(1)接收不同數量的參數,(2)傳遞不同型態的參數,(3)傳回不同型態的參數。
10.1.1 多載一般函數 多載(overloading)就是重複定義多個相同名稱的函數,但這些函數的功能不完全相同。 範例 10.1.1 多載一般函數 多載(overloading)就是重複定義多個相同名稱的函數,但這些函數的功能不完全相同。 範例 int area(int length, int width); //第一個area { return length * width; } 範例待續……
10.1.1 多載一般函數 (續) 範例續 double area(int radius) //第二個area函數 { 10.1.1 多載一般函數 (續) 範例續 double area(int radius) //第二個area函數 { return 3.1415926 * pow(radius, 2); } int main() int rectangleArea = area(3, 5); //呼叫第一個area函數 double circleArea = area(5); //呼叫第二個area函數 return 0; //正常結束程式
10.1.2 多載成員函數 多載函數的情況包括:(1)接收不同數量的參數,(2)傳遞不同型態的參數,(3)傳回不同型態的參數。 範例一 10.1.2 多載成員函數 多載函數的情況包括:(1)接收不同數量的參數,(2)傳遞不同型態的參數,(3)傳回不同型態的參數。 範例一 class Cuboid //宣告長方體類別 { private: int length; //Cuboid的資料成員1 int width; //Cuboid的資料成員2 int height; //Cuboid的資料成員3
10.1.2 多載成員函數 (續) 範例續 public: int area() { //錯誤,Multiple declaration 10.1.2 多載成員函數 (續) 範例續 public: int area() { //錯誤,Multiple declaration return length * width; } return 2 * (length * width + width * height + height * length); };
10.1.2 多載成員函數 (續) 範例二 class Cuboid //宣告長方體類別 { 10.1.2 多載成員函數 (續) 範例二 class Cuboid //宣告長方體類別 { int length; //Cuboid的資料成員1 int width; //Cuboid的資料成員2 int height; //Cuboid的資料成員3 public: void setSide(int l, int w) //設定長方形邊長 length = l; width = w; height = 0; }
10.1.2 多載成員函數 (續) 範例續 void setSide(int l, int w, int h) //設定長方體邊長 { 10.1.2 多載成員函數 (續) 範例續 void setSide(int l, int w, int h) //設定長方體邊長 { length = l; width = w; height = h; } int area() //計算長方體表面積函數 return 2 * (length * width + width * height + height * length); };
10.1.3 多載建立者函數 在類別中可以多載(overload)建立者函數,也就是定義多個建立者函數,每個建立者函數可含有不同個數的參數。 10.1.3 多載建立者函數 在類別中可以多載(overload)建立者函數,也就是定義多個建立者函數,每個建立者函數可含有不同個數的參數。 範例 class Timer { int seconds; public: Timer() { //定義無參數建立者 seconds = 0;} Timer(int s) { //定義整數參數建立者 seconds = s;}
10.1.3 多載建立者函數 (續) 範例續 Timer(char *t) { //定義指標參數建立者 10.1.3 多載建立者函數 (續) 範例續 Timer(char *t) { //定義指標參數建立者 seconds = atoi(t);} }; int main() { char str[20] = "250"; Timer t1; //t1.seconds = 0 Timer t2(10); //t2.seconds = 10 Timer t3(str); //t3.seconds = 250 return 0; //正常結束程式 }
10.2 多載運算符號 在C++ 語言中,<< 運算符號可以配合cout敘述作為字串輸出運算符號,也可以作為左移位元運算符號;同理,>> 運算符號可以配合cin敘述作為字串輸入運算符號,也可以作為右移位元運算符號。這就是運算符號多載(operator overloading)。 運算符號多載(operator overloading),就是要再定義這些運算符號,使它們也能接受使用者自定的資料型態與物件。
10.2.1 多載運算符號限制 可以被多載的運算符號包括表10.1算術運算符號、表10.2關係與邏輯運算符號、表10.3位元運算符號、表10.4指定運算符號、表10.5特殊運算符號。 表中同時提供這些運算符號在C++ 資料庫中的內建功能、範例與說明,設計師為自定資料型態多載這些符號時,必須保持它們原來的功能,否則將會造成語法錯誤訊息。 例如,將 + 多載為減法運算符號,編譯時會出現語法錯誤訊息。
10.2.2 運算符號函數 運算符號函數可以是類別成員函數或非類別成員函數。當非成員函數或非friend函數要存取私用區(private)或保護區(protected)的資料時,必須先呼叫公用區(public)的set或get成員函數,如此將會降低程式的性能。 所以為了得到更好的性能,可使用friend函數,friend雖然不是類別成員函數但仍可直接存取私用區(private)或保護區(protected)的資料。
10.2.3 多載 >> 運算符號 friend istream &operator>>(istream&傳回參數, 類別名稱 物件參數) 範例 class Test { private: int a, b; //定義private變數 public: Test() { a = b = 0; }
10.2.3 多載 >> 運算符號 (續) 範例續 Test(int n, int m) { a = n; b = m; } 10.2.3 多載 >> 運算符號 (續) 範例續 Test(int n, int m) { a = n; b = m; } }; int main() { Test s1; cin >> s1; //錯誤不能輸入Test型態資料 cout << s1; //錯誤不能輸出Test型態資料 return 0; //正常結束程式 }
10.2.4 多載 << 運算符號 friend ostream &operator<<(ostream&傳回參數, 類別名稱 物件參數) 範例 class Test { private: int a, b; //定義private變數 public: Test() { a = b = 0; }
10.2.4 多載 << 運算符號 (續) 範例續 Test(int n, int m) { a = n; b = m; } 10.2.4 多載 << 運算符號 (續) 範例續 Test(int n, int m) { a = n; b = m; } friend istream& operator>>(istream& in, Test& obj); friend ostream& operator<<(ostream& out, Test& obj); }; istream& operator>>(istream& in, Test& obj) { cout << "請輸入a與b之值:"; in >> obj.a >> obj.b; return in; }
10.2.4 多載 << 運算符號 (續) 範例續 10.2.4 多載 << 運算符號 (續) 範例續 ostream& operator<<(ostream& out, Test& obj) { out << "a 與 b 的值:" << endl; out << obj.a << " " << obj.b << endl; return out; } int main() { Test s1; cin >> s1; //若輸入2 3 cout << s1; //則輸出2 3 return 0; //正常結束程式
10.2.5 多載雙運算元符號 傳回型態 operator運算符號(類別型態 物件參數) 10.2.5 多載雙運算元符號 傳回型態 operator運算符號(類別型態 物件參數) 傳回型態 operator運算符號(類別1 物件1, 類別2 物件2) 範例 class Test { int a, b; //定義private變數 public: Test() { a = b = 0; } Test(int n, int m) { a = n; b = m; } Test operator+(Test); //宣告多載 + 號 };
10.2.5 多載雙運算元符號 (續) 範例一續 Test Test::operator+(Test obj) { //定義多載 + 號 10.2.5 多載雙運算元符號 (續) 範例一續 Test Test::operator+(Test obj) { //定義多載 + 號 Test temp; temp.a = a + obj.a; //a=s1.a, obj.a=s2.a temp.b = b + obj.b; //b=s1.b, obj.b=s2.b return temp; } int main() { Test s1(2, 3), s2(4, 5), s3; s3 = s1 + s2; //s1.operator+(s2) return 0; //正常結束程式
10.2.5 多載雙運算元符號 (續) 範例二 class Test { int a; //定義private變數 public: 10.2.5 多載雙運算元符號 (續) 範例二 class Test { int a; //定義private變數 public: Test() { a = 0; } Test(int n) { a = n; } bool operator>(Test); //宣告多載 > 號 }; bool Test::operator>(Test obj) { //定義多載 > 號 if (a > obj.a) return true; else return false; }
10.2.5 多載雙運算元符號 (續) 範例二續 int main() { Test s1(2), s2(5); 10.2.5 多載雙運算元符號 (續) 範例二續 int main() { Test s1(2), s2(5); if (s1 > s2) //呼叫多載 > 函數 cout << "s1 > s2"; else cout << "s1 < s2"; return 0; //成功結束程式 }
10.2.6 多載單運算元符號 傳回型態 operator運算符號() 傳回型態 operator運算符號(類別型態 物件參數) 範例 10.2.6 多載單運算元符號 傳回型態 operator運算符號() 傳回型態 operator運算符號(類別型態 物件參數) 範例 class Test { int a; //定義private變數 public: Test(int n) { a = n; } bool operator !(); //宣告多載 ! 號 };
10.2.6 多載單運算元符號 (續) 範例續 bool Test::operator!() { //定義多載 ! 號 10.2.6 多載單運算元符號 (續) 範例續 bool Test::operator!() { //定義多載 ! 號 if (a != 0) {return true;} else {return false;} } int main() { Test s1(5); if (!s1) {cout << "s1 != 0"; } //呼叫多載 ! 符號函數 else {cout << "s1 == 0";} return 0; //正常結束程式
10.2.7 多載前置運算符號 傳回型態 operator運算符號() 範例 class Test { 10.2.7 多載前置運算符號 傳回型態 operator運算符號() 範例 class Test { int a, b; //定義private變數 public: Test() { a = b = 0; } Test(int n, int m) { a = n; b = m; } Test operator++(); //宣告前置 ++x 號 };
10.2.7 多載前置運算符號 (續) 範例續 Test Test::operator++() //定義前置 ++x 號 { 10.2.7 多載前置運算符號 (續) 範例續 Test Test::operator++() //定義前置 ++x 號 { return Test(++a, ++b); } int main() Test s1(2, 3), s2; s2 = ++s1; //等於s1.operator++() return 0; //正常結束程式
10.2.8 多載後置運算符號 傳回型態 operator運算符號(int) 範例 class Test { 10.2.8 多載後置運算符號 傳回型態 operator運算符號(int) 範例 class Test { int a, b; //定義private變數 public: Test() { a = b = 0; } Test(int n, int m) { a = n; b = m; } Test operator++(int); //宣告後置 x++ 號 };
10.2.8 多載後置運算符號 (續) 範例續 Test Test::operator++(int) //定義後置 x++ 號 { 10.2.8 多載後置運算符號 (續) 範例續 Test Test::operator++(int) //定義後置 x++ 號 { return Test(a++, b++); } int main() Test s1(2, 3), s2; s2 = s1++; //s2.a=s1.a=2, s2.b=s1.b=3 //s1.a=++s1.a=3, s1.b=++s1.b=4 return 0; //正常結束程式
10.3 轉換型態 轉換型態 目的位置 來源位置 基本型態轉換基本型態 使用C++ 內建函數 基本型態轉換類別型態 使用建立者函數 無 10.3 轉換型態 轉換型態 目的位置 來源位置 基本型態轉換基本型態 使用C++ 內建函數 基本型態轉換類別型態 使用建立者函數 無 類別型態轉換基本型態 使用多載型態符號函數 類別型態轉換類別型態
10.3.1 基本型態轉基本型態 float型態的fracfeet轉成int型態的feet int feet; 10.3.1 基本型態轉基本型態 float型態的fracfeet轉成int型態的feet int feet; float fracfeet = 3.280833 * 3.5; feet = int(fracfeet); //float轉成int int型態的fracfeet轉成float型態的fracfeet float fracfeet = inch / 10; fracfeet = float(feet); //feet從int轉為float
10.3.2 基本型態轉類別型態 float型態的資料轉成Distance型態 const float MTF = 3.280833f; 10.3.2 基本型態轉類別型態 float型態的資料轉成Distance型態 const float MTF = 3.280833f; class Distance //宣告Distance類別 { int feet; float inch; public: Distance (int f, float in) //宣告一參數建立者 feet = f; inch = in; }
10.3.2 基本型態轉類別型態 (續) 範例續 Distance (float meter) { //宣告二參數建立者 10.3.2 基本型態轉類別型態 (續) 範例續 Distance (float meter) { //宣告二參數建立者 float fracfeet = MTF * meter; feet = (int)fracfeet; inch = 10 * (fracfeet - feet); } }; int main() { Distance d(0, 0); //呼叫二個參數的建立者 float m = 3.5; //m = 3.5 m d = m; //呼叫一個參數的建立者 return 0; //正常結束程式
10.3.3 類別型態轉基本型態 Distance型態的資料轉成float型態 範例 const float MTF = 3.280833; 10.3.3 類別型態轉基本型態 Distance型態的資料轉成float型態 範例 const float MTF = 3.280833; class Distance //宣告Distance類別 { int feet; float inch; public: Distance (int f, float in) //Distance類別建立者 feet = f; inch = in; }
10.3.3 類別型態轉基本型態 (續) 範例續 operator float() { //多載float型態函數 10.3.3 類別型態轉基本型態 (續) 範例續 operator float() { //多載float型態函數 float fracfeet = inch / 10; fracfeet = float(feet); return fracfeet / MTF; } }; int main() { Distance d(2, 3); //呼叫Distance建立者 float m; //宣告浮點數變數m m = d; //呼叫operator float函數 return 0; //正常結束程式
10.3.4 類別型態轉類別型態 Polar型態的資料轉成Cartesian型態 10.3.4 類別型態轉類別型態 Polar型態的資料轉成Cartesian型態 class Cartesian { //宣告 Cartesian 類別 double x; double y; public: Cartesian () {x = y = 0.0;} }; class Polar { //宣告Polar類別 double radius; double angle; Polar(double r, double a) { radius = r; angle = a; }
10.3.4 類別型態轉類別型態 (續) 範例續 operator Cartesian() { //多載Cartesian函數 10.3.4 類別型態轉類別型態 (續) 範例續 operator Cartesian() { //多載Cartesian函數 double xx, yy; xx = radius * cos(angle); yy = radius * sin(angle); return Cartesian(xx, yy); } }; int main() { Polar p(2.0, 35.0); //建立極座標p點位置 Cartesian c; //建立平面座標c c = p; //呼叫Cartesian函數 return 0; //正常結束程式
10.3.4 類別型態轉類別型態 (續) Polar型態的資料轉成Cartesian型態 範例 10.3.4 類別型態轉類別型態 (續) Polar型態的資料轉成Cartesian型態 範例 class Polar //宣告Polar類別 { double radius; double angle; public: Polar(double r, double a) { radius = r; angle = a; } double getr() {return radius;} double geta() {return angle;} };
10.3.4 類別型態轉類別型態 (續) class Cartesian { //宣告Cartesian類別 double x; 10.3.4 類別型態轉類別型態 (續) class Cartesian { //宣告Cartesian類別 double x; double y; public: Cartesian() {x = y = 0.0;} Cartesian(double a, double b) {x = a; y = b;} Cartesian operator = (Polar p) { //定義多載 = 號函數 double r = p.getr(); double a = p.geta(); x = r * cos(a); y = r * sin(a); return Cartesian(x, y); } };
10.3.4 類別型態轉類別型態 (續) 範例 int main() { Polar p(2.0, 35.0); //建立極座標p點位置 10.3.4 類別型態轉類別型態 (續) 範例 int main() { Polar p(2.0, 35.0); //建立極座標p點位置 Cartesian c; //建立平面座標c c = p; //呼叫多載 = 號函數 return 0; //正常結束程式 }