OPP C++ (phần 2)

Chia sẻ: Van Trung | Ngày: | Loại File: PDF | Số trang:20

0
109
lượt xem
45
download

OPP C++ (phần 2)

Mô tả tài liệu
  Download Vui lòng tải xuống để xem tài liệu đầy đủ

Các tham số có giá trị mặc định chỉ được cho trong prototype của hàm và không được lặp lại trong định nghĩa hàm (vì trình biên dịch sẽ dùng các thông tin trong protype chứ không phải trong định nghĩa hàm để tạo một lệnh gọi)

Chủ đề:
Lưu

Nội dung Text: OPP C++ (phần 2)

  1. 13: 1
  2. MyFunc(1);// OK, các tham số b, c và d lấy giá trị mặc định MyFunc(5, 7); // OK, các tham số c và d lấy giá trị mặc định MyFunc(5, 7, , 8); // Lỗi do các tham số bị bỏ phải liên tiếp nhau 2.2.12 Phép tham chiếu Trong C, hàm nhận tham số là con trỏ đòi hỏi chúng ta phải thận trọng khi gọi hàm. Chúng ta cần viết hàm hoán đổi giá trị giữa hai số như sau: void Swap(int *X, int *Y); { int Temp = *X; *X = *Y; *Y = *Temp; } Để hoán đổi giá trị hai biến A và B thì chúng ta gọi hàm như sau: Swap(&A, &B); Rõ ràng cách viết này không được thuận tiện lắm. Trong trường hợp này, C++ đưa ra một kiểu biến rất đặc biệt gọi là biến tham chiếu (reference variable). Một biến tham chiếu giống như là một bí danh của biến khác. Biến tham chiếu sẽ làm cho các hàm có thay đổi nội dung các tham số của nó được viết một cách thanh thoát hơn. Khi đó hàm Swap() được viết như sau: void Swap(int &X, int &Y); { int Temp = X; X = Y; Y = Temp ; } Chúng ta gọi hàm như sau : Swap(A, B); Với cách gọi hàm này, C++ tự gởi địa chỉ của A và B làm tham số cho hàm Swap(). Cách dùng biến tham chiếu cho tham số của C++ tương tự như các tham số được khai báo là Var trong ngôn ngữ 32
  3. Pascal. Tham số nà được gọi l tham số ki tham chi (referenc parameter Như vậy b tham ày là iểu iếu ce r). biến chiếu có cú pháp nh sau : ó hư data_typ & variab ype ble_name; Trong đó: đ data_type: Kiểu dữ liệu của biến. K variable_na ame: Tên của biến a Khi dùn biến tham chiếu cho tham số chỉ có địa chỉ củ nó được g đi chứ kh ng m t ủa gởi hông phải là toàn bộ cấu trúc hay đối tượ đó như h c ợng hình 2.14, đi này rất h dụng khi chúng ta gở cấu trúc và đối iều hữu i ởi tượng lớ cho một hàm. ớn h Hình 2. .14: Một tha số kiểu th chiếu nh một tham chiếu tới m biến đượ chuyển ch tham số am ham hận m một ợc ho của hàm. . Ví dụ 2 2.12: Chương trình hoán đổi giá trị củ hai biến. g ủa CT2_12.CPP C 1: 1 #includ 2: 2 //prototype 3 void Swa ap(int &X,i int &Y); 4: 4 5: 5 int main() 6: 6 { 7: 7 in X = 10, Y = 5; nt 8: 8 cout
  4. 9: 9 Sw wap(X,Y); 10: 1 cout
  5. thể so s sánh các biến tham chiếu với nhau (p tương th về kiểu tham chiếu) n u phải hích ). Ví dụ 22.13: Mọi tha tác trên tr bí danh c ao rên chính là thao tác trên biến gốc của nó o ó. CT2_13.CPP C 1: 1 #includ 2: 2 int main() 3: 3 { 4: 4 int X = 3; 5: 5 int &Y = X; // la bí d /Y danh của X 6: 6 int Z = 100; 7: 7 8: 8 cout
  6. 1: 1 #includ 2: 2 int main() 3: 3 { 4: 4 int X = 3; 5: 5 int &Y = X; // la bí d /Y danh của X 6: 6 7: 7 cout
  7. CT2_15.CPP C 1: 1 #includ 2: 2 3: 3 int X = 4; 4: 4 //prototype 5: 5 int & M MyFunc(); 6: 6 7: 7 int main() 8: 8 { 9: 9 cou ut
  8. đến biến tham chiếu Tuy nhiên chúng ta có thể khai bá một biến t n u. n ó áo tham chiếu v biến con t như về trỏ đoạn mã sau: m int X; X int *P = &X; * int * & Ref = P; 2.2 2.13 Phép đa năng hóa (Overloadin : a ( ng) Với ngô ngữ C++, chúng ta có thể đa năng hóa các hà và các toá tử (operat ôn , ó g àm án tor). Đa năng hóa là g phương pháp cung cấp nhiều hơ một định nghĩa cho tê hàm đã ch trong cùn một phạm vi. Trình g ơn ên ho ng m biên dịc sẽ lựa chọ phiên bản thích hợp c hàm hay toán tử dựa trên các tha số mà nó được gọi. ch ọn n của am 2.2.13.1 Đa năng h các hàm (Functions overloadin : 1 hóa m s ng) Trong ngôn ngữ C cũng như mọi ng ngữ máy tính khác, m hàm đều phải có mộ tên phân g gôn y mỗi u ột biệt. Đôi kh đây là một điều phiều t hi t toái. Chẳng hạn như tron ngôn ngữ C, có rất nh hàm ng ữ hiều trả về trị tuy đối của m tham số là số, vì cần thiết phải có tên phân b nên C ph có hàm yệt một n ó biệt hải riêng cho m kiểu dữ li số, do vậ chúng ta c tới ba hàm khác nhau để trả về trị tuyệt đối mỗi iệu ậy có m u ị của một tham số : m int abs(int i)); long labs(lo l); ong double fabs( (double d); Tất cả các hàm này đều cùng thực h một chứ năng nên c h hiện ứa chúng ta thấ điều này n ấy nghịch lý khi phải có b tên khác nhau. C++ g quyết điều này bằng cách cho ph chúng ta tạo ra các ba giải g hép a hàm khác nh có cùng một tên. Đâ chính là đ năng hóa h hau ây đa hàm. Do đó trong C++ cchúng ta có thể định ngh lại các hà trả về trị tuyệt đối để thay thế các hàm trên n sau : hĩa àm ể c như int abs(int i)); long abs(lon l); ng double abs(d double d); 16: Ví dụ 2.1 CT2_16. .CPP 1: #include 2: #include 3: 4: int MyAbs(i int X); 5: long MyAbs( (long X); 6: d double MyAb bs(double X); 7: 8: int main() 9: { 38
  9. 10: int X = -7; 11: long Y = 200000l; 12: double Z = -35.678; 13: cout
  10. Chúng ta ch ví dụ 2.16 , kết quả ở hình 2.19 hạy Hình 2.19: K quả của v dụ 2.16 H Kết ví Trình biên dịch dựa vào sự kh nhau về số các tham số, kiểu của các tham số để có thể x định h d hác m a s xác chính xác phiên bản cài đặt n của hàm MyAbs() thí hợp với m lệnh gọi hàm được c chẳng h b nào ích một i cho, hạn n như: MyA Abs(-7); //Gọi hàm int MyyAbs(int) MyA Abs(-7l); //Gọ hàm long MyAbs(long ọi g) MyA Abs(-7.5); //G hàm doub MyAbs( Gọi ble (double) Quá ttrình tìm đượ hàm được đa năng hó cũng là qu trình được dùng để gi quyết các trường ợc c óa uá c iải c hợp nnhập nhằng của C++. Ch c hẳng hạn như nếu tìm thấ một phiên bản định nghĩa nào đó của một ư ấy n n hàm được đa năn hóa mà có kiểu dữ liệu các tham số của nó trù với kiểu các tham số đã gởi tới đ ng ó u s ùng ố trong lệnh gọi hàm thì phiên bản hàm đó sẽ được gọi Nếu không trình biên dịch C++ sẽ gọi đến g i. g d phiên bản nào cho phép chuy kiểu dễ d n yển dàng nhất. Abs(‘c’); //G int MyAb MyA Gọi bs(int) MyA Abs(2.34f); / //Gọi double MyAbs(dou e uble) Các phép chhuyển kiểu c sẵn sẽ đượ ưu tiên hơ các phép chuyển kiểu mà chúng t tạo ra có ợc ơn u ta (chúng ta sẽ xem xét các phép chuy kiểu tự tạ ở chương 3). ẽ c yển ạo Chúng ta cũ có thể lấy địa chỉ của một hàm đ được đa nă hóa sao cho bằng m cách ũng a đã ăng một nào đó chún ta có thể l cho trình biên dịch C++ biết đượ chúng ta cần lấy địa c của ng làm h C ợc chỉ phiên bản hàm nào có tr rong định ng ghĩa. Chẳng hạn như: int (*pf1)(int); long (*pf2)(long g g); int (*pf3)(double e); pf1 = MyAbs; // /Trỏ đến hàm int MyAbs m s(int) pf2 = MyAbs; // /Trỏ đến hàm long MyAb m bs(long) pf3 = MyAbs; // /Lỗi!!! (khôn có phiên bản hàm nào để đối sánh ng b o h) Các giới hạn của việc đa năng hó các hàm: c óa • Bấ kỳ hai hàm nào trong t các hàm đã đa năng p có các t ất m tập phải tham số khác nhau u. 40
  11. • Các hàm đa năng hóa với danh sách các tham số cùng kiểu chỉ dựa trên kiểu trả về của hàm thì trình biên dịch báo lỗi. Chẳng hạn như, các khai báo sau là không hợp lệ: void Print(int X); int Print(int X); Không có cách nào để trình biên dịch nhận biết phiên bản nào được gọi nếu giá trị trả về bị bỏ qua. Như vậy các phiên bản trong việc đa năng hóa phải có sự khác nhau ít nhất về kiểu hoặc số tham số mà chúng nhận được. • Các khai báo bằng lệnh typedef không định nghĩa kiểu mới. Chúng chỉ thay đổi tên gọi của kiểu đã có. Chúng không ảnh hưởng tới cơ chế đa năng hóa hàm. Chúng ta hãy xem xét đoạn mã sau: typedef char * PSTR; void Print(char * Mess); void Print(PSTR Mess); Hai hàm này có cùng danh sách các tham số, do đó đoạn mã trên sẽ phát sinh lỗi. • Đối với kiểu mảng và con trỏ được xem như đồng nhất đối với sự phân biệt khác nhau giữa các phiên bản hàm trong việc đa năng hóa hàm. Chẳng hạn như đoạn mã sau se phát sinh lỗi: void Print(char * Mess); void Print(char Mess[]); Tuy nhiên, đối với mảng nhiều chiều thì có sự phân biệt giữa các phiên bản hàm trong việc đa năng hóa hàm, chẳng hạn như đoạn mã sau hợp lệ: void Print(char Mess[]); void Print(char Mess[][7]); void Print(char Mess[][9][42]); • const và các con trỏ (hay các tham chiếu) có thể dùng để phân biệt, chẳng hạn như đoạn mã sau hợp lệ: void Print(char *Mess); void Print(const char *Mess); 41
  12. 2.2.13.2 Đa năng h các toán tử (Operat 2 hóa n tors overloa ading) : Trong ngôn ngữ C, khi chúng ta tự t ra một kiểu dữ liệu m chúng t thực hiện c thao tạo mới, ta các tác liên quan đến kiểu d liệu đó thư n dữ ường thông qua các hàm điều này tr nên không thoải q m, rở g mái. Ví dụ 2.17: Chương trìn cài đặt các phép toán cộng và trừ số phức nh c CT2_17. .CPP 1: #include 2: /* Định ngh hĩa số phứ */ ức 3: typedef str ruct 4: { 5: double Real; 6: double Imaginary y; 7: }Complex; 8: 9: Complex Se etComplex(double R,d double I); 10: Complex Ad ddComplex(Complex C1 1,Complex C C2); 11: Complex Su ubComplex(Complex C1 1,Complex C C2); 12: void Displ layComplex(Complex C C); 13: 14: int main(v void) 15: { 16: Complex C1,C2,C3,C4; x 17: 18: C1 = Se etComplex(1.0,2.0); 19: etComplex(-3.0,4.0); C2 = Se ; 20: printf( ("\nSo phuc thu nhat t:"); 21: Display yComplex(C1); 42
  13. 22: printf("\nSo phuc thu hai:"); 23: DisplayComplex(C2); 24: C3 = AddComplex(C1,C2); //Hơi bất tiện !!! 25: C4 = SubComplex(C1,C2); 26: printf("\nTong hai so phuc nay:"); 27: DisplayComplex(C3); 28: printf("\nHieu hai so phuc nay:"); 29: DisplayComplex(C4); 30: return 0; 31: } 32: 33: /* Đặt giá trị cho một số phức */ 34: Complex SetComplex(double R,double I) 35: { 36: Complex Tmp; 37: 38: Tmp.Real = R; 39: Tmp.Imaginary = I; 40: return Tmp; 41: } 42: /* Cộng hai số phức */ 43: Complex AddComplex(Complex C1,Complex C2) 44: { 45: Complex Tmp; 46: 47: Tmp.Real = C1.Real+C2.Real; 48: Tmp.Imaginary = C1.Imaginary+C2.Imaginary; 43
  14. 49: return Tmp; 50: } 51: 52: /* Trừ hai số phức */ i 53: Complex Su ubComplex(Complex C1 1,Complex C C2) 54: { 55: Complex Tmp; x 56: 57: Tmp.Rea = C1.Real-C2.Real al l; 58: Tmp.Ima aginary = C1.Imagina ary-C2.Imag ginary; 59: return Tmp; 60: } 61: 62: /* Hiển th số phức */ hị 63: void Displ layComplex(Complex C C) 64: { 65: printf( ("(%.1lf,%.1lf)",C.R Real,C.Imag ginary); 66: } Chúng ta ch ví dụ 2.17, kết quả ở hình 2.20 hạy Hình 2.20: Kết qu của ví dụ 2.17 uả Trong chươ trình ở ví dụ 2.17, ch ơng í húng ta nhận thấy với các hàm vừa cài đặt dùng đ cộng và n c để trừ hai số ph 1+2i và –3+4i; ngườ lập trình hoàn toàn kh hức ời h hông thoải m khi sử dụn bởi vì mái ng thực chất thao tác cộng và trừ là các toán tử chứ không phải là hàm. Để khắc phục y điểm c ứ i yếu này, trong C++ cho phép chúng ta c thể định n C có nghĩa lại chứ năng của các toán tử đ có sẵn ức c đã 44
  15. một cách tiệ lợi và tự n ện nhiên hơn rấ nhiều. Điều này gọi là đa năng hóa toán tử. Khi đó ất u a h chương trình ở ví dụ 2.1 được viết như sau: h 17 t Ví dụ 2.18: CT2_18. .CPP 1: #include 2: // Định ngh hĩa số phứ ức 3: typedef str ruct 4: { 5: double Real; 6: double Imaginary y; 7: }Complex; 8: 9: Complex Se etComplex(double R,d double I); 10: void Displ layComplex(Complex C C); 11: Complex op perator + (Complex C C1,Complex C2); 12: Complex op perator - (Complex C C1,Complex C2); 13: 14: int main(v void) 15: { 16: Complex C1,C2,C3,C4; x 17: 18: C1 = Se etComplex(1.0,2.0); 19: etComplex(-3.0,4.0); C2 = Se ; 20: cout
  16. 25: C4 = C1 - C2; 26: cout
  17. 52: 53: //Trừ hai số phức 54: Complex op perator - (Complex C C1,Complex C2) 55: { 56: Complex Tmp; x 57: 58: Tmp.Rea = C1.Real-C2.Real al l; 59: Tmp.Ima aginary = C1.Imagina ary-C2.Imag ginary; 60: return Tmp; 61: } 62: 63: //Hiển thị số phức ị 64: void Displ layComplex(Complex C C) 65: { 66: cout
  18. C4 = C3 + C1 - C2; Chúng ta nhận thấy rằng cả hai lệnh đều cho cùng kết quả nhưng lệnh của C++ thì dễ hiểu hơn. C++ làm được điều này bằng cách tạo ra các hàm định nghĩa cách thực hiện của một toán tử cho các kiểu dữ liệu tự định nghĩa. Một hàm định nghĩa một toán tử có cú pháp sau: data_type operator operator_symbol ( parameters ) { ……………………………… } Trong đó: data_type: Kiểu trả về. operator_symbol: Ký hiệu của toán tử. parameters: Các tham số (nếu có). Trong chương trình ví dụ 2.18, toán tử + là toán tử gồm hai toán hạng (gọi là toán tử hai ngôi; toán tử một ngôi là toán tử chỉ có một toán hạng) và trình biên dịch biết tham số đầu tiên là ở bên trái toán tử, còn tham số thứ hai thì ở bên phải của toán tử. Trong trường hợp lập trình viên quen thuộc với cách gọi hàm, C++ vẫn cho phép bằng cách viết như sau: C3 = operator + (C1,C2); C4 = operator - (C1,C2); Các toán tử được đa năng hóa sẽ được lựa chọn bởi trình biên dịch cũng theo cách thức tương tự như việc chọn lựa giữa các hàm được đa năng hóa là khi gặp một toán tử làm việc trên các kiểu không phải là kiểu có sẵn, trình biên dịch sẽ tìm một hàm định nghĩa của toán tử nào đó có các tham số đối sánh với các toán hạng để dùng. Chúng ta sẽ tìm hiểu kỹ về việc đa năng hóa các toán tử trong chương 4. Các giới hạn của đa năng hóa toán tử: • Chúng ta không thể định nghĩa các toán tử mới. • Hầu hết các toán tử của C++ đều có thể được đa năng hóa. Các toán tử sau không được đa năng hóa là : Toán tử Ý nghĩa :: Toán tử định phạm vi. .* Truy cập đến con trỏ là trường của struct hay thành 48
  19. viên của class. . Truy cập đến trường của struct hay thành viên của class. ?: Toán tử điều kiện sizeof và chúng ta cũng không thể đa năng hóa bất kỳ ký hiệu tiền xử lý nào. • Chúng ta không thể thay đổi thứ tự ưu tiên của một toán tử hay không thể thay đổi số các toán hạng của nó. • Chúng ta không thể thay đổi ý nghĩa của các toán tử khi áp dụng cho các kiểu có sẵn. • Đa năng hóa các toán tử không thể có các tham số có giá trị mặc định. Các toán tử có thể đa năng hoá: + - * / % ^ ! = < > += -= ^= &= |= > = == != , -> ->* Các toán tử được phân loại như sau : Các toán tử một ngôi : * & ~ ! ++ -- sizeof (data_type) Các toán tử này được định nghĩa chỉ có một tham số và phải trả về một giá trị cùng kiểu với tham số của chúng. Đối với toán tử sizeof phải trả về một giá trị kiểu size_t (định nghĩa trong stddef.h) Toán tử (data_type) được dùng để chuyển đổi kiểu, nó phải trả về một giá trị có kiểu là data_type. 49
  20. Các toán tử hai ngôi: * / % + - >> < >= >=

CÓ THỂ BẠN MUỐN DOWNLOAD

Đồng bộ tài khoản