Bài giảng Lập trình hướng đối tượng và C++

pdf 337 trang phuongnguyen 4391
Bạn đang xem 20 trang mẫu của tài liệu "Bài giảng Lập trình hướng đối tượng và C++", để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên

Tài liệu đính kèm:

  • pdfbai_giang_lap_trinh_huong_doi_tuong_va_c.pdf

Nội dung text: Bài giảng Lập trình hướng đối tượng và C++

  1. PHM VĂN T (Ch biên) NGUYN HIU CƯNG LLPP TTRRÌÌNNHH HHƯƯNNGG ððII TTƯƯNNGG VVÀÀ CC++ NHÀ XUT BN GIAO THÔNG VN TI
  2. LI NÓI ðU Lp trình hưng ñi tưng và C ++ là mt môn hc quan trng ñi vi sinh viên ngành Công ngh thông tin và mt s ngành hc khác. Lp trình hưng ñi tưng là phương pháp lp trình ch ño hin nay trong công nghip phn mm và tư tưng hưng ñi tưng ñưc áp dng trong hu ht các ngôn ng lp trình hin ñi như C ++ , Visual C ++ , C#, Java Phương pháp lp trình ph bin nht trong nhng năm 70 và 80 ca th k trưc là lp trình cu trúc. ðó là phương pháp t chc, phân chia chương trình thành các hàm, th tc. Thông qua các ngôn ng như Pascal và C, ña s nhng ngưi làm Tin hc ñã khá quen bit vi phương pháp lp trình này. Tuy nhiên phương pháp lp trình này cũng dn bc l nhiu hn ch. Phương pháp lp trình hưng ñi tưng ñã khc phc ñưc nhng hn ch ca lp trình cu trúc và m ra mt giai ñon phát trin mi trong công nghip phn mm. Lp trình hưng ñi tưng da trên vic t chc chương trình thành các lp. Khác vi hàm và th tc, lp là mt ñơn v bao gm c d liu và các phương thc x lý. Vì vy lp có th mô t các thc th mt cách chân thc, ñy ñ và cht ch hơn. Ngôn ng C ra ñi năm 1973 vi mc ñích ban ñu là ñ vit h ñiu hành Unix trên máy tính mini PDP. Sau ñó C ñã ñưc s dng rng rãi trên nhiu loi máy tính khác nhau và ñã tr thành mt ngôn ng lp trình cu trúc rt ñưc ưa chung. ð ñưa C vào th gii hưng hưng ñi tưng, năm 1980 B. Stroustrup ñã ++ cho ra ñi mt ngôn ng mi gi là C , là mt s phát trin mnh m ca ngôn ng C. Ngôn ng C ++ là mt ngôn ng lai, tc là nó cho phép t chc chương trình theo c các lp và các hàm. Có th nói C ++ ñã thúc ñy ngôn ng C vn ñã rt thuyt phc ñi vào th gii lp trình hưng ñi tưng và C++ ñã tr thành ngôn ng hưng ñi tưng mnh và ñưc s dng rng rãi nht t nhng năm 1990. Giáo trình này s trình by mt cách h thng các khái nim ca lp trình hưng ñi tưng ñưc cài ñt trong C ++ như lp, ñi tưng, s tha k, tính tương ng bi, khuôn hình và các kh năng mi trong xây dng, s dng hàm như: ñi tham chiu, ñi mc ñnh, hàm trùng tên, hàm toán t. Cui mi chương ñu có các bài tp nhng mc ñ khác nhau ñ ñc gi t rèn luyn thêm. Các vn ñ phc tp thưng ñòi hi phi phân tích và thit k tương ñi ñy ñ trưc khi có th vit chương trình. Tuy giáo trình này không tp trung vào phân tích 2
  3. thit k, nhưng trong ph lc 4 chúng tôi cũng gii thiu vn tt v phương pháp phân tích, thit k hưng ñi tưng. Cun sách gm 9 chương và 4 ph lc. Chương 1 hưng dn cách làm vic vi phn mm TC ++ 3.0 ñ th nghim các chương trình, trình by sơ lưc v các phương pháp lp trình và gii thiu mt s m rng ñơn gin ca C ++ . Chương 2 trình by các kh năng mi trong vic xây dng và s dng hàm trong C ++ như bin tham chiu, ñi có kiu tham chiu, ñi có giá tr mc ñnh, hàm trc tuyn, hàm trùng tên, hàm toán t. Chương 3 nói v mt khái nim trung tâm ca lp trình hưng ñi tưng. Chương 4 trình bày chi tit hơn v ñnh nghĩa chng các toán t Chương 5 trình by các vn ñ to dng, sao chép, hu b các ñi tưng và các vn ñ khác có liên quan. Chương 6 trình by mt khái nim quan trng to nên kh năng mnh ca lp trình hưng ñi tưng trong vic phát trin, m rng phn mm, ñó là kh năng tha k ca các lp. Chương 7 trình by mt khái nim quan trng khác trong lp trình hưng ñi tưng là tính tương ng bi và phương thc o. Chương 8 nói v vic t chc vào/ra trong C ++ . Chương 9 trình by v khuôn hình (template) trong C++ . Ph lc 1 trình by các phép toán trong C ++ và th t ưu tiên ca chúng. Ph lc 2 trình by v bng mã ASCII và mã quét ca các ký t. Ph lc 3 là tp hp mt s câu hi trc nghim và ñáp án ñ bn ñc t kim tra li kin thc. Ph lc 4 trình by mt cách ngn gn phương pháp phân tích, thit k và lp trình hưng ñi tưng. Cui cùng là danh mc mt s thut ng chuyên ngành s dng trong giáo trình này cùng v trí tham chiu ñ ñc gi tin tra cu, và mt s tài liu tham kho chính. Ni dung chính ca giáo trình ñưc PGS. TS. Phm Văn t biên son da trên nn cun “C ++ & lp trình hưng ñi tưng” ca tác gi, nhưng có mt s b sung và sa cha. ThS. Nguyn Hiu Cưng biên son chương 4, ph lc 3, các bài tp cui mi chương và hiu chnh giáo trình. 3
  4. Khi vit giáo trình này chúng tôi ñã ht sc c gng ñ giáo trình ñưc hoàn chnh, song chc không tránh khi thiu sót, vì vy chúng tôi rt mong nhn ñưc s góp ý ca ñc gi. Các tác gi Chương 1 CÁC KHÁI NIM CƠ BN Chương này trình by các vn ñ sau: Cách s dng phn mm Turbo C ++ 3.0 Tóm lưc v các phương pháp lp trình cu trúc và lp trình hưng ñi tưng Nhng m rng ca C ++ so vi C § 1. LÀM VIC VI TURBO C ++ 3.0 Các ví d trong giáo trình này ñưc vit và thc hin trên môi trưng Turbo C ++ (TC ++ phiên bn 3.0). Sau khi cài ñt (gi s vào thư mc C:\TC) thì trong thư mc TC s gm có các thư mc con sau: C:\TC\BGI cha các tp ñuôi BGI và CHR C:\TC\BIN cha các tp chương trình (ñuôi EXE) như TC, TCC, TLIB, TLINK, C:\TC\INCLUDE cha các tp tiêu ñ ñuôi H C:\TC\LIB cha các tp ñuôi LIB, OBJ ð vào môi trưng ca TC ++ ch cn thc hin tp chương trình TC.EXE trong thư mc C:\TC\BIN . Sau khi vào môi trưng TC ++ chúng ta thy vùng son tho chương trình và h menu chính ca TC ++ (gn ging như h menu quen thuc ca Turbo C). H menu ca TC ++ gm các menu: File, Edit, Search, Run, Compile, Debug, Project, Options, Window, Help. Cách son tho, biên dch và chy chương trình trong TC ++ cũng ging như trong TC, ngoi tr ñim sau: Tp chương trình trong h son tho ca TC ++ có ñuôi mc ñnh là CPP còn trong TC thì tp chương trình có ñuôi là C. Trong TC ++ có th thc hin c chương trình C và C ++ . § 2. NGÔN NG C VÀ C ++ Có th nói C ++ là s m rng ñáng k ca C. ðiu ñó có nghĩa là ngoài nhng kh năng mi ca C ++ , mi kh năng, mi khái nim trong C ñu dùng ñưc trong C ++ . Vì trong C ++ s dng gn như toàn b các khái nim, ñnh nghĩa, các kiu d liu, các cu trúc lnh, các hàm và các công c khác ca C, nên s thun li hơn nu ñc 4
  5. gi ñã bit s dng tương ñi thành tho ngôn ng C. Giáo trình này ch yu tp trung vào các khái nim lp trình hưng ñi tưng cùng ngôn ng C ++ , và do ñó nó s không trình bày li các ch ñ cơ bn trong ngôn ng C như các kiu d liu, các cu trúc ñiu khin, Vì C ++ là s m rng ca C, nên bn thân mt chương trình C ñã là chương trình C++ . Tuy nhiên Trình biên dch TC ++ yêu cu mi hàm chun dùng trong chương trình ñu phi khai báo nguyên mu bng mt câu lnh #include, trong khi ñiu này không bt buc ñi vi Trình biên dch ca TC. Trong C ta có th dùng mt hàm chun mà b qua câu lnh #include ñ khai báo nguyên mu ca hàm ñưc dùng. ðiu này không báo li khi biên dch, nhưng có th dn ñn kt qu sai khi chy chương trình. Ví d khi biên dch chương trình sau trong môi trưng C s không gp các dòng cnh báo (warning) và thông báo li (error). Nhưng khi chy s nhn ñưc kt qu sai. #include void main() { float a,b,c,p,s; printf("\nNhap a, b, c "); scanf("%f%f%f",&a,&b,&c); p=(a+b+c)/2; s= sqrt(p*(pa)*(pb)*(pc)); printf("\nDien tich = %0.2f",s); getch(); } Nu biên dch chương trình này trong TC ++ s nhn ñưc các thông báo li sau: Error: Funtion ‘sqrt’ should have a prototype Error: Funtion ‘getch’ should have a prototype ð bin chương trình trên thành mt chương trình C ++ cn: + ðt tên chương trình vi ñuôi CPP + Thêm hai câu lnh #include ñ khai báo nguyên mu cho các hàm sqrt và getch: #include #include § 3. LP TRÌNH CU TRÚC VÀ LP TRÌNH HƯNG ðI TƯNG 3.1. Phương pháp lp trình cu trúc 5
  6. Tư tưng chính ca lp trình cu trúc là t chc chương trình thành các chương trình con. Trong PASCAL có hai kiu chương trình con là th tc (procedure) và hàm (fuction). Trong C ch có mt loi chương trình con là hàm. Hàm là mt ñơn v chương trình ñc lp dùng ñ thc hin mt phn vic nào ñó như: Nhp s liu, in kt qu hay thc hin mt s tính toán. Hàm cn có ñi và các bin, mng cc b dùng riêng cho hàm. Vic trao ñi d liu gia các hàm thc hin thông qua các ñi và các bin toàn b. Các ngôn ng như C, PASCAL là các ngôn ng cho phép trin khai phương pháp lp trình cu trúc. Mt chương trình cu trúc gm các cu trúc d liu (như bin, mng, bn ghi, ) và các hàm, th tc. Nhim v chính ca vic t chc thit k chương trình cu trúc là t chc chương trình thành các hàm, th tc. Ví d xét yêu cu sau: Vit chương trình nhp to ñ (x,y) ca mt dy ñim, sau ñó tìm mt cp ñim cách xa nhau nht. Trên tư tưng ca lp trình cu trúc có th t chc chương trình như sau: + S dng hai mng thc toàn b x và y ñ cha to ñ dy ñim + Xây dng hai hàm: Hàm nhapsl dùng ñ nhp to ñ n ñim, hàm này có mt ñi là bin nguyên n và ñưc khai báo như sau: void nhapsl(int n); Hàm do_dai dùng ñ tính ñ dài ñon thng ñi qua 2 ñim có ch s là i và j , nó ñưc khai báo như sau: float do_dai(int i, int j); Chương trình C cho bài toán trên ñưc vit như sau: #include #include #include float x[100], y[100]; float do_dai(int i, int j) { return sqrt(pow(x[i]x[j],2)+pow(y[i]y[j],2)); } void nhapsl(int n) { int i; for (i=1;i<=n;++i) { printf("\nNhap toa do x, y cua diem thu %d : ",i); scanf("%f%f", &x[i], &y[i]); 6
  7. } } void main() { int n,i,j,imax,jmax; float d,dmax; printf("\nSo diem n = "); scanf("%d",&n); nhapsl(n); dmax=do_dai(1,2); imax=1; jmax=2; for (i=1;i dmax) { dmax=d; imax=i; jmax=j; } } printf("\nDoan thang lon nhat co do dai bang: %0.2f",dmax); printf("\n Di qua 2 diem co chi so la %d va %d",imax,jmax); getch(); } 3.2. Phương pháp lp trình hưng ñi tưng Khái nim trung tâm ca lp trình hưng ñi tưng là lp (class). Có th xem lp là s kt hp các thành phn d liu và các hàm. Cũng có th xem lp là s m rng ca cu trúc (struct) trong C bng cách ñưa thêm vào các phương thc (methods) hay còn gi là hàm thành viên (member functions). Mt lp ñưc ñnh nghĩa như sau: class Tên_lp { // Khai báo các thành phn d liu // Khai báo các phương thc }; 7
  8. Các phương thc có th ñưc vit (xây dng) bên trong hoc bên ngoài (phía dưi) phn ñnh nghiã lp. Cách vit mt phương thc tương t như vit mt hàm, ngoi tr quy tc sau: Khi xây dng mt phương thc bên ngoài ñnh nghĩa lp thì trong dòng ñu tiên cn dùng tên lp và hai du hai chm (::) ñt trưc tên phương thc ñ ch rõ phương thc ñó thuc lp nào. Vì phương thc và các thành phn d liu thuc cùng mt lp, hơn na phương thc ñưc lp lên ct ñ x lý các thành phn d liu, nên trong thân ca phương thc có quyn truy nhp ñn các thành phn d liu (ca cùng lp). Sau khi ñnh nghĩa mt lp, có th dùng tên lp ñ khai báo các bin kiu lp hay còn gi là ñi tưng. Mi ñi tưng s có các thành phn d liu và các phương thc. Li gi mt phương thc cn cha tên ñi tưng ñ xác ñnh phương thc thc hin t ñi tưng nào. Mt chương trình hưng ñi tưng s bao gm các lp có quan h vi nhau. Vic phân tích, thit k chương trình theo phương pháp hưng ñi tưng nhm thit k, xây dng các lp. T khái nim lp ny sinh hàng lot khái nim khác như: Thành phn d liu, phương thc, phm vi, s ñóng gói, hàm to, hàm hu, s tha k, lp cơ s, lp dn xut, tương ng bi, phương thc o, Thit k hưng ñi tưng là tp trung xác ñnh các lp ñ mô t các thc th ca bài toán. Mi lp ñưa vào các thành phn d liu ca thc th và xây dng luôn các phương thc ñ x lý d liu. Như vy vic thit k chương trình xut phát t các ni dng các vn ñ ca bài toán. Các ngôn ng thun tuý hưng ñi tưng (như Smalltalk) ch h tr các khái nim v lp, không có các khái nim hàm. C++ là ngôn ng lai, nó cho phép s dng c các công c ca lp và hàm. ð minh ho các khái nim va nêu v lp trình hưng ñi tưng ta tr li xét bài toán tìm ñ dài ln nht ñi qua 2 ñim. Trong bài toán này ta gp mt thc th là dy ñim. Xây dng lp dãy ñim (daydiem), trong ñó các thành phn d liu ca lp dy ñim gm: + Bin nguyên n là s ñim ca dy + Con tr x kiu thc tr ñn vùng nh cha dy hoành ñ + Con tr y kiu thc tr ñn vùng nh cha dy tung ñ Các phương thc cn ñưa vào theo yêu cu bài toán gm: + Nhp to ñ mt ñim + Tính ñ dài ñon thng ñi qua 2 ñim Dưi ñây là chương trình vit theo thit k hưng ñi tưng. ð thc hin chương trình này nh ñt tên tp có ñuôi CPP. Xem chương trình ta thy thêm mt ñiu mi trong C ++ là: Các khai báo bin, mng có th vit bt kỳ ch nào trong chương trình (tt nhiên phi trưc khi s dng bin, mng). #include 8
  9. #include #include #include class daydiem { public: int n; float *x, *y; float do_dai(int i, int j) { return sqrt(pow(x[i]x[j],2)+pow(y[i]y[j],2)); } void nhapsl(void); // khai báo phương thc }; void daydiem::nhapsl(void) // ñnh nghĩa (xây dng) phương thc { int i; printf("\nSo diem n = "); scanf("%d",&n); x=(float*)malloc((n+1)*sizeof(float)); y=(float*)malloc((n+1)*sizeof(float)); for (i=1;i<=n;++i) { printf("\nNhap toa do x, y cua diem thu %d : ",i); scanf("%f%f",&x[i],&y[i]); } } void main() { daydiem p; int n,i,j; int imax,jmax; float d, dmax; p.nhapsl(); n=p.n; dmax=p.do_dai(1,2); imax=1;jmax=2; 9
  10. for (i=1;i dmax) { dmax=d; imax=i; jmax=j; } } printf("\nDoan thang lon nhat co do dai bang: %0.2f",dmax); printf("\n Di qua 2 diem co chi so la %d va %d",imax,jmax); getch(); } § 4. MT S M RNG ðƠN GIN CA C ++ SO VI C Trong mc này trình by mt s m rng ca C ++ , tuy ñơn gin nhưng ñem li khá nhiu tin li. 4.1. Vit các dòng ghi chú Trong C ++ vn có th vit các dòng ghi chú trong các du /* và */ như trong C. Cách vit này cho phép vit các ghi chú trên nhiu dòng hoc trên mt dòng. Ngoài ra trong C ++ còn cho phép vit ghi chú trên mt dòng sau hai du gch chéo rt tin li, ví d: int x,y ; // Khai báo 2 bin thc 4.2. Khai báo linh hot Trong C tt c các câu lnh khai báo bin, mng cc b phi ñt ti ñu khi. Do vy nhiu khi v trí khai báo và v trí s dng ca bin khá xa nhau, gây khó khăn trong vic kim soát chương trình. C ++ ñã khc phc nhưc ñim này bng cách cho phép các lnh khai báo bin, mng có th ñt bt kỳ ch nào trong chương trình trưc khi các bin, mng ñó ñưc s dng. Ví d chương trình nhp mt dy s thc ri sp xp theo th t tăng dn có th vit trong C ++ như sau: #include #include 10
  11. void main() { int n; // khai bao n printf("\n So phan tu cua day n = "); scanf("%d",&n); float *x= (float*)malloc((n+1)*sizeof(float)); for (int i=1;i x[j]) { float tg=x[i]; x[i]=x[j]; x[j]=tg; } printf("\nDay sau khi sap xep\n"); for (i=1;i<=n;++i) printf("%0.2f ",x[i]); } 4.3. Toán t ép kiu Toán t này ñưc vit trong C như sau: (Kiu) biu_thc Trong C ++ vn có th dùng cách vit này. Ngoài ra C ++ cho phép vit mt cách khác tin li hơn như sau: Kiu(biu_thc) Ví d ñ in ra kt qu chính xác ca phép chia hai bin nguyên (a chia cho b) trong C ++ ta cn thc hin ép kiu: printf("Ket qua = % ", float(a)/b); 4.4. Hng có kiu ð to ra mt hng có kiu, ta s dng t khoá const ñt trưc mt khai báo có khi gán giá tr. Sau ñây là mt s ví d: + Hng nguyên: 11
  12. const int maxsize = 1000; int a[maxsize] ; + Cu trúc hng: typedef struct { int x, y ; // To ñ ca ñim int mau ; // Mã mu ca ñim } DIEM ; const DIEM d = {320, 240, 15}; Chương trình dưi ñây minh ho cách dùng hng có kiu. Chương trình to mt cu trúc hng (kiu DIEM) mô t ñim gia màn hình ñ ho vi mu trng. ðim này ñưc hin th trên màn hình ñ ho. #include #include #include typedef struct { int x,y; int mau; } DIEM; void main() { int mh=0, mode=0; initgraph(&mh,&mode,""); int loi=graphresult(); if (loi) { printf("\nLoi do hoa: %s",grapherrormsg(loi)); getch(); exit(0); } const DIEM gmh = {getmaxx()/2,getmaxy()/2,WHITE}; // khai bao hang putpixel(gmh.x, gmh.y, gmh.mau); closegraph(); } Chú ý: + Có th dùng các hàm ñ gán giá tr cho các hng có kiu (trong chương trình trên dùng các hàm getmax và getmaxy). 12
  13. + Mi câu lnh nhm thay ñi giá tr hng có kiu ñu b báo li khi biên dch chương trình. Ví d nu trong chương trình ñưa vào câu lnh: gmh.x=200; thì khi dch chương trình s nhn ñưc thông báo li như sau: Cannot modify a const object 4.5. Các kiu char và int Trong C mt hng ký t ñưc xem là nguyên do ñó nó có kích thưc hai byte, ví d trong C: sizeof(‘A’) = sizeof(int) = 2 Còn trong C ++ mt hng ký t ñưc xem là giá tr kiu char và có kích thưc mt byte. Như vy trong C ++ thì: sizeof(‘A’) = sizeof(char) = 1 4.6. Ly ña ch các phn t mng thc hai chiu Trong TC 2.0 không cho phép dùng phép & ñ ly ña ch các phn t mng thc hai chiu. Vì vy khi nhp d liu cho mt phn t ca ma trn thc (dùng scanf) ta phi nhp qua mt bin trung gian sau ñó mi gán cho các phn t mng. Trong TC ++ 3.0 cho phép ly ña ch các phn t mng thc hai chiu, do ñó có th dùng scanf ñ nhp trc tip vào các phn t mng. Chương trình C ++ dưi ñây s minh ho ñiu này. Chương trình nhp mt ma trn thc cp mxn và xác ñnh phn t có giá tr ln nht. #include void main() { float a[20][20], smax; int m,n,i,j, imax, jmax; puts( "Cho biet so hang va so cot cua ma tran: ") ; scanf("%d%d",&m,&n) ; for (i=1;i<=m;++i) for (j=1;j<=n;++j) { printf("\na[%d][%d]= ",i,j); scanf("%f",&a[i][j]); // Ly ña ch phn t mng thc hai chiu } 13
  14. smax = a[1][1]; imax=1; jmax=1; for (i=1;i<=m;++i) for (j=1;j<=n;++j) if (smax<a[i][j]) { smax = a[i][j]; imax=i ; jmax = j; } puts( "\n\nPhan tu max:" ); printf("\nco gia tri = %6.1f", smax); printf("\nTai hang %d cot %d " ,imax, jmax) ; } 4.7. Hàm trong C ++ Trong C ++ có nhiu m rng, ci tin v hàm làm cho vic xây dng và s dng hàm rt tin li. ðiu này s trình by k trong chương sau. Trong mc này ch thng kê mt s ñim mi v hàm mà C ++ ñưa vào. ði kiu tham chiu Trong C, ñ nhn kt qu ca hàm qua các ñi ta cn dùng ñi con tr, làm cho vic xây dng cũng như s dng hàm khá phin phc. Trong C ++ ñưa vào ñi kiu tham chiu dùng ñ cha kt qu ca hàm, khin cho vic to lp cũng như s dng hàm ñơn gin hơn. ði tham chiu const ði tham chiu có ñc ñim là các câu lnh trong thân hàm có th truy nhp ti và d dàng làm cho giá tr ca nó thay ñi. Nhiu khi ta mun dùng ñi kiu tham chiu ch ñ tăng tc ñ trao ñi d liu gia các hàm, không mun dùng nó ñ cha kt qu ca hàm. Khi ñó có th dùng ñi tham chiu const ñ bo toàn giá tr ca ñi trong thân hàm. ði có giá tr mc ñnh Trong nhiu trưng hp ngưi dùng vit mt li gi hàm nhưng còn chưa bit nên chn giá tr nào cho các ñi . ð khc phc khó khăn này, C ++ ñưa ra gii pháp ñi có giá tr mc ñnh. Khi xây dng hàm, ta gán giá tr mc ñnh cho mt s ñi. Ngưi dùng nu không cung cp giá tr cho các ñi này, thì hàm s dùng giá tr mc ñnh. Hàm trc tuyn (inline) ði vi mt ñon chương trình nh (s lnh không ln) thì vic thay các ñon chương trình này bng các li gi hàm s làm cho chương trình gn nh ñôi chút nhưng làm tăng thi gian máy. Trong các trưng hp này có th dùng hàm trc tuyn va gim kích thưc chương trình ngun, va không làm tăng thi gian chy máy. Các hàm trùng tên (ñnh nghĩa chng các hàm) 14
  15. ð ly giá tr tuyt ñi ca mt s, trong C cn lp ra nhiu hàm vi tên khác nhau, ví d abs cho s nguyên, fabs cho s thc, labs cho s nguyên dài, cabs cho s phc. ðiu này rõ ràng gây phin toái cho ngưi s dng. Trong C ++ cho phép xây dng các hàm trùng tên nhưng khác nhau v kiu ñi. Như vy ch cn lp mt hàm ñ ly giá tr tuyt ñi cho nhiu kiu d liu khác nhau. ðnh nghĩa chng toán t Vic dùng các phép toán thay cho mt li gi hàm rõ ràng làm cho chương trình ngn gn, sáng sa hơn nhiu. Ví d ñ thc hin phép cng 2 ma trn nu dùng phép cng và vit: C = A + B ; thì rt gn vi toán hc. Trong C++ cho phép dùng các phép toán chun ñ ñt tên cho các hàm (gi là ñnh nghĩa chng toán t), sau ñó có th thay li gi hàm bng các phép toán như nói trên. § 5. VÀO RA TRONG C ++ 5.1. Các toán t và phương thc xut nhp ð in d liu ra màn hình và nhp d liu t bàn phím, trong C ++ vn có th dùng các hàm printf và scanf (như ñã ch ra trong các chương trình C ++ các mc trên). Ngoài ra trong C ++ còn dùng toán t xut ñ ñưa giá tr các biu thc ra màn hình: cout > bin >> >> bin; ð nhp mt dy không quá n ký t và cha vào mng h (kiu char) có th dùng phương thc cin.get như sau: cin.get(h,n); Chú ý: + Toán t nhp cin >> s ñ li ký t chuyn dòng ‘\n’ trong b ñm, ký t này có th làm trôi phương thc cin.get. ð khc phc tình trng trên cn dùng phương thc cin.ignore ñ b qua mt ký t chuyn dòng như sau: cin.ignore(1); + ð s dng các toán t và phương thc nói trên cn khai báo tp tiêu ñ: #include 15
  16. Chương trình sau minh ho vic s dng các công c vào ra mi ca C ++ ñ nhp mt danh sách n thí sinh. D liu mi thí sinh gm h tên, các ñim toán, lý, hoá. Sau ñó in danh sách thí sinh theo th t gim ca tng ñim. #include #include void main() { struct { char ht[25]; float t,l,h,td; } ts[50],tg; int n,i,j; cout > n ; for (i=1;i > ts[i].t >> ts[i].l >> ts[i].h ; ts[i].td = ts[i].t + ts[i].l + ts[i].h ; } for (i=1;i<=n1;++i) for (j=i+1;j<=n;++j) if (ts[i].td < ts[j].td ) { tg=ts[i]; ts[i]=ts[j]; ts[j]=tg; } cout << "\nDanh sach thi sinh sau khi sap xep " ; for (i=1;i<=n;++i) { cout << "\n Ho ten: " << ts[i].ht; cout << " Tong diem: " << ts[i].td; } 16
  17. getch(); } 5.2. ðnh dng khi in ra màn hình ð quy ñnh s thc (float, double) ñưc in ra có ñúng p ch s sau du chm thp phân, ta s dng ñng thi các hàm sau: setiosflags(ios::showpoint); // Bt c hiu showpoint setprecision(p); Các hàm này cn ñt trong toán t xut như sau: cout Tr li chương trình trên ta thy danh sách thí sinh in ra s không thng ct. ð khc phc ñiu này cn vit li ñon chương trình in như sau: cout #include void main() 17
  18. { float a[20][20], smax; int m,n,i,j,imax, jmax; cout > m >> n ; for (i=1;i > a[i][j] ; } smax = a[1][1]; imax= jmax= 1; for (i=1;i<=m;++i) for (j=1;j<=n;++j) if (smax<a[i][j]) { smax = a[i][j]; imax=i ; jmax = j; } cout << "\n\n Ma tran" ; cout << setiosflags(ios::showpoint) << setprecision(1) ; for (i=1;i<=m;++i) for (j=1;j<=n;++j) { if (j==1) cout << '\n' ; cout << setw(6) << a[i][j]; } cout << "\n\n" << "Phan tu max:" << '\n' ; cout << "co gia tri = " << setw(6) << smax; cout << "\nTai hang: " << imax << " cot: " << jmax ; } § 6. CÁC KIU CU TRÚC, HP VÀ LIT KÊ 6.1. Tên sau t khoá struct ñưc xem như tên kiu cu trúc 18
  19. Trong C ++ mt kiu cu trúc cũng ñưc ñnh nghĩa như C theo mu: struct Tên_kiu_ct { // Khai báo các thành phn ca cu trúc } ; Sau ñó ñ khai báo các bin, mng cu trúc, trong C dùng mu sau: struct Tên_kiu_ct danh sách bin, mng cu trúc ; Như vy trong C, tên vit sau t khoá struct chưa phi là tên kiu và chưa có th dùng ñ khai báo. Trong C ++ xem tên vit sau t khoá struct là tên kiu cu trúc và có th dùng nó ñ khai báo. Như vy ñ khai báo các bin, mng cu trúc trong C ++ , ta có th dùng mu sau: Tên_kiu_ct danh sách bin, mng cu trúc ; Ví d: ðnh nghĩa kiu cu trúc TS (thí sinh) gm các thành phn ht (h tên), sobd (s báo danh), dt (ñim toán), dl (ñim lý), dh (ñim hoá) và td (tng ñim), sau ñó khai báo bin cu trúc h và mng cu trúc ts. struct TS { char ht [25]; long sobd; float dt, dl, dh, td; } ; TS h, ts[1000] ; 6.2. Tên sau t khoá union ñưc xem như tên kiu hp Trong C ++ mt kiu hp (union) cũng ñưc ñnh nghĩa như C theo mu: union Tên_kiu_hp { // Khai báo các thành phn ca hp } ; Sau ñó ñ khai báo các bin, mng kiu hp , trong C dùng mu sau: union Tên_kiu_hp danh sách bin, mng kiu hp ; Như vy trong C, tên vit sau t khoá union chưa phi là tên kiu và chưa có th dùng ñ khai báo. Trong C ++ xem tên vit sau t khoá union là tên kiu hp và có th dùng nó ñ khai báo. Như vy ñ khai báo các bin, mng kiu hp, trong C ++ có th dùng mu sau: Tên_kiu_hp danh sách bin, mng kiu hp ; 19
  20. 6.3. Kiu lit kê (enum) Cũng ging như cu trúc và hp, tên vit sau t khoá enum ñưc xem là kiu lit kê và có th dùng ñ khai báo, ví d: enum MAU { xanh, do, tim, vang } ; // ðnh nghĩa kiu MAU MAU m, dsm[10] ; // Khai báo các bin, mng kiu MAU Các giá tr kiu lit kê (enum) là các s nguyên. Do ñó có th thc hin các phép tính trên các giá tr enum, có th in các giá tr enum, có th gán giá tr enum cho bin nguyên, ví d: MAU m1 , m2 ; int n1, n2 ; m1 = tim ; m2 = vang ; n1 = m1 ; // n1 = 2 n2 = m1 + m2 ; // n2 = 5 printf (“\n %d “ , m2 ); // in ra s 3 Chú ý: Không th gán trc tip mt giá tr nguyên cho mt bin enum mà phi dùng phép ép kiu, ví d: m1 = 2 ; // li m1 = MAU(2) ; // ñúng § 7. CP PHÁT B NH Trong C ++ có th s dng các hàm cp phát b nh ñng ca C như: hàm malloc ñ cp phát b nh, hàm free ñ gii phóng b nh ñưc cp phát. Ngoài ra trong C ++ còn ñưa thêm toán t new ñ cp phát b nh và toán t delete ñ gii phóng b nh ñưc cp phát bi new. 7.1. Cách dùng toán t new ñ cp phát b nh như sau: Trưc ht cn khai báo mt con tr ñ cha ña ch vùng nh s ñưc cp phát: Kiu *p; ñây Kiu có th là: + Các kiu d liu chun ca C ++ như int, long, float, double, char, + Các kiu t ñnh nghĩa như: mng, hp, cu trúc, lp, Sau ñó dùng toán t new theo mu: p = new Kiu ; // Cp phát b nh cho mt bin (mt phn t) p = new Kiu[n] ; // Cp phát b nh cho n phn t Ví d ñ cp phát b nh cho mt bin thc ta dùng câu lnh sau: float *px = new float ; ð cp phát b nh cho 100 phn t nguyên ta dùng các câu lnh: int *pn = new int[100] ; 20
  21. 7.2. Hai cách kim tra s thành công ca new Khi dùng câu lnh: Kiu *p = new Kiu[n] ; hoc câu lnh: Kiu *p = new Kiu ; ñ cp phát b nh s xut hin mt trong hai kh năng: cp phát thành công hoc không thành công. + Nu thành công thì p s cha ña ch ñu vùng nh ñưc cp phát. + Nu không thành công thì p = NULL. ðon chương trình sau minh ho mt cách kim tra li cp phát b nh: double *pd ; int n ; cout > n ; pd = new double[n] ; if (pd==NULL) // Kim tra { cout << “ Li cp phát b nh “ exit (0) ; } Cách th hai ñ kim tra s thành công ca toán t new là dùng con tr hàm: _new_handler ñưc ñnh nghĩa trong tp “new.h”. Khi gp li trong toán t new (cp phát không thành công) thì chương trình s thc hin mt hàm nào ñó do con tr _new _handler tr ti. Cách dùng con tr này như sau: + Xây dng mt hàm dùng ñ kim tra s thành công ca new + Gán tên hàm này cho con tr _new_handler Như vy hàm kim tra s ñưc gi mi khi có li xy ra trong toán t new. ðon chương trình kim tra theo cách th nht có th vit theo cách th hai như sau: void kiem_tra_new(void) // Lp hàm kim tra { cout << “ Li cp phát b nh “ exit (0) ; } _new _handler = kiem_tra_new // Gán tên hàm cho con tr 21
  22. double *pd ; int n ; cout > n ; pd = new double[n] ; // Khi xy ra li s gi hàm kim_tra_new Chú ý: Có th dùng lnh gán ñ gán tên hàm x lý li cho con tr _new _handler như trong ñon chương trình trên, hoc dùng hàm: set_new_handler(Tên hàm) ; 7.3. Toán t delete dùng ñ gii phóng vùng nh ñưc cp phát bi new Nu p là con tr xác ñnh vùng nh ñưc cp bng new, thì ñ gii phóng vùng nh ñã cp ta dùng câu lnh sau: delete p ; Ví d: float p, *px ; p = new float; // Cp phát b nh cho mt phn t thc px = new float[2000] ; // Cp phát b nh cho mng 2000 phn t thc // S dng b nh ñưc cp phát delete p; // Gii phóng b nh ca mt phn t delete [] px ; // Gii phóng b nh ca c mng 7.4. Các chương trình minh ho Chương trình th nht minh ho cách dùng new ñ cp phát b nh cha n thí sinh. Mi thí sinh là mt cu trúc gm các trưng ht (h tên), sobd (s báo danh) và td (tng ñim). Chương trình s nhp n, cp phát b nh cha n thí sinh, kim tra li cp phát b nh (dùng cách 1); sau ñó nhp n thí sinh, sp xp thí sinh theo th t gim ca tng ñim, in danh sách thí sinh sau khi sp xp, và cui cùng là gii phóng b nh ñã cp phát. #include #include #include #include struct TS { char ht[20]; long sobd; float td; } ; 22
  23. void main(void) { TS*ts ; int n; cout > n; ts = new TS[n+1]; if(ts==NULL) { cout > ts[i].sobd ; cout > ts[i].td ; } for (i=1;i<=n1;++i) for (int j=i+1;j<=n;++j) if (ts[i].td < ts[j].td) { TS tg=ts[i]; ts[i]=ts[j]; ts[j]=tg; } cout << setiosflags(ios::showpoint) << setprecision(1) ; for (i=1;i<=n;++i) cout << "\n" << setw(20) << ts[i].ht << setw(6)<< ts[i].sobd <<setw(6)<< ts[i].td; delete ts; getch(); } 23
  24. Chương trình th hai minh ho cách dùng con tr _new_handler ñ kim tra s thành công ca toán t new. Chương trình s cp phát b nh cho mt mng con tr và s theo dõi khi nào thì không ñ b nh ñ cp phát. #include #include #include #include int k; void loi_bo_nho(void) { cout << "\nLoi bo nho khi cap phat bo nho cho q[" << k << "]"; getch(); exit(0); } void main() { double *q[100] ; long n; clrscr(); set_new_handler(loi_bo_nho) ; // Hoc _new_handler=loi_bo_nho; n=10000; for ( k=0;k<100;++k) q[k] = new double[n]; cout << "Khong loi"; getch(); } BÀI TP CHƯƠNG 1 Bài 1. Vit chương trình nhp mt s t nhiên n. Kim tra xem n có phi s nguyên t không. Bài 2. Vit chương trình nhp mt dãy s thc. In các s dương trên mt dòng và các s âm trên dòng tip theo. Bài 3. Vit chương trình nhp mt dãy s thc. Sp xp dãy s trên theo th t tăng dn. Bài 4. Vit chương trình nhp hai dãy s thc ñu ñưc sp tăng dn. Ghép hai dãy s trên thành mt dãy cũng ñưc sp tăng dn. Bài 5. Trong mt trưng trung hc, hoc sinh bt buc phi hc ba môn toán, lý và hoá. Ngoài ra hc sinh nam hc thêm môn k thut còn hc sinh n hc thêm môn n 24
  25. công. Vit chương trình thc hin các công vic: Nhp h tên, gii tính và ñim ca n hc sinh. In s liu v các hc sinh ra màn hình. Bài 6. Trong mc 7.1 ñã ñ cp ñn vic cp phát b nh ñng cho mt bin và mt mng mt chiu. Bài này yêu cu cao hơn: Vit chương trình cp phát b nh ñng cho mt mng hai chiu, sau ñó nhp d liu vào mng ñó và in kt qu ra màn hình. 25
  26. CHƯƠNG 2 HÀM TRONG C ++ Chương này trình by nhng kh năng mi ca C ++ trong vic xây dng và s dng các hàm. ðó là: Bin tham chiu và vic truyn d liu cho hàm bng tham chiu ði có giá tr mc ñnh Hàm trc tuyn ðnh nghĩa chng các hàm ðnh nghĩa chng các toán t § 1. BIN THAM CHIU 1.1. Hai loi bin dùng trong C Trưc khi nói ñn bin tham chiu, chúng ta nhc li hai loi bin ñã gp trong C là: + Bin giá tr dùng ñ cha d liu (nguyên, thc, ký t, ) + Bin con tr dùng ñ cha ña ch Các bin này ñu ñưc cung cp b nh và có ña ch. Ví d câu lnh khai báo: double x , *px; s to ra bin giá tr kiu double là x và bin con tr kiu double là px. Bin x có vùng nh 8 byte, bin px có vùng nh 4 byte (nu dùng mô hình b nh Large). Bin x dùng ñ cha giá tr kiu double, ví d lnh gán: x = 3.14; s cha giá tr 3.14 vào bin x. Bin px dùng ñ cha ña ch ca mt bin thc, ví d câu lnh: px = &x ; s lưu tr ña ch ca bin x vào con tr px. 1.2. Bin tham chiu Trong C ++ cho phép s dng loi bin th ba là bin tham chiu (reference variable). So vi hai loi bin nói trên thì bin tham chiu có nhng ñc ñim sau: + Bin tham chiu không ñưc cp phát b nh, không có ña ch riêng. + Nó dùng làm bí danh (alias) cho mt bin (kiu giá tr) nào ñó và nó s dng vùng nh ca bin này. Ví d câu lnh: float u, v, &r = u ; 26
  27. to ra các bin thc u, v và bin tham chiu thc r. Bin r không ñưc cp phát b nh riêng, nó ch là mt tên khác (bí danh) ca u và nó dùng chung vùng nh ca bin u. Khi r là bí danh ca u thì ta nói r tham chiu ñn bin u. Như vy hai thut ng trên ñưc hiu như nhau. Khi r là bí danh ca u thì r dùng chung vùng nh ca u, do ñó : + Trong mi câu lnh, vit u hay vit r ñu có ý nghĩa như nhau, vì ñu truy nhp ñn cùng mt vùng nh. + Có th dùng bin tham chiu ñ truy nhp ñn mt bin kiu giá tr. Ví d: int u, v, &r = u; r = 10 ; // u=10 cout << u ; // in ra s 10 r++ ; // u = 11 ++ u ; // r = 12 cout << r ; // in ra s 12 v = r ; // v=12 & r ; // Cho ña ch ca u Vài chú ý v bin tham chiu: + Bin tham chiu thưng ñưc s dng làm ñi ca hàm ñ cho phép hàm truy nhp ñn các tham s bin trong li gi hàm. + Vì bin tham chiu không có ña ch riêng, nó ch là bí danh ca mt bin kiu giá tr nên trong khai báo phi ch rõ nó tham chiu ñn bin nào. Ví d nu khai báo: double &x ; thì Trình biên dch s báo li: Reference variable ‘x’ must be initialized + Bin tham chiu có th tham chiu ñn mt phn t mng, ví d: int a[10] , &r = a[5]; r = 25 ; // khi ñó a[5] = 25 + Không cho phép khai báo mng tham chiu + Bin tham chiu có th tham chiu ñn mt hng. Khi ñó nó s s dng vùng nh ca hng và nó có th làm thay ñi giá tr cha trong vùng nh này. Ví d nu khai báo: int &s = 23 ; thì Trình biên dch ñưa ra cnh báo: Temporary used to initialize 's' 27
  28. Tuy nhiên chương trình vn làm vic. Các câu lnh dưi ñây vn thc hin và cho kt qu như sau: s++; cout << "\ns= " << s; // In ra s=24 § 2. TRUYN GIÁ TR CHO HÀM THEO THAM CHIU 2.1. Hàm trong C Trong C ch có mt cách truyn d liu cho hàm theo giá tr, ñưc thc hin như sau: + Cp phát vùng nh cho các ñi. + Gán giá tr các tham s trong li gi hàm cho các ñi sau ñó hàm làm vic trên vùng nh ca các ñi ch không liên quan gì ñn các tham s. Như vây chương trình s to ra các bn sao (các ñi) ca các tham s và hàm s thao tác trên các bn sao này, ch không làm vic trc tip vi các tham s. Phương pháp này có nhng nhưc ñim chính: Tn kém v thi gian và b nh vì phi to ra các bn sao, và không thao tác trc tip trên các tham s, vì vy không làm thay ñi ñưc giá tr các tham s. 2.2. Truyn giá tr cho hàm theo tham chiu C++ cung cp thêm cách truyn d liu cho hàm theo tham chiu bng cách dùng ñi là bin tham chiu hoc ñi là hng tham chiu. Cách này có ưu ñim: Không cn to ra các bn sao ca các tham s, do ñó tit kim b nh và thi gian chy máy, và hàm s thao tác trc tip trên vùng nh ca các tham s, do ñó có th d dàng thay ñi giá tr các tham s khi cn. 2.3. Mi quan h gia ñi và tham s trong li gi hàm Nu ñi là bin hoc hng tham chiu kiu gì thì tham s (trong li gi hàm) phi là bin hoc phn t mng kiu ñó. Ví d: + ði là bin (hoc hng) tham chiu kiu double, thì tham s là bin hoc phn t mng kiu double + ði là bin (hoc hng) tham chiu kiu cu trúc, thì tham s là bin hoc phn t mng kiu cu trúc 2.4. Các chương trình minh ho /* Chương trình 1: Gm các hàm: + Nhp dy s kiu double + Hoán v 2 bin kiu double + Sp xp dy s kiu double theo th t tăng dn Chương trình s nhp mt dy s và in dy sau khi sp xp */ 28
  29. #include #include #include void nhapds(double *a, int n) { for (int i=1; i > a[i] ; } } // Hàm hoán v, dùng ñi tham chiu void hv(double &x, double &y) { double tg=x; x=y; y= tg; } void sapxep(double * a, int n) { for (int i=1; i a[j]) hv(a[i],a[j]); } void main() { double x[100]; int i, n; cout > n; nhapds(x,n); sapxep(x,n); for (i=1;i<=n;++i) printf("\n%0.1lf",x[i]); getch(); 29
  30. } /* Chương trình 2: Gm các hàm: + Nhp dy cu trúc (mi cu trúc cha d liu mt thí sinh) + Hoán v 2 bin cu trúc + Sp xp dy thí sinh theo th t gim ca tng ñim + In mt cu trúc (in h tên và tng ñim) Chương trình s nhp d liu mt danh sách thí sinh, nhp ñim chun và in danh sách thí sinh trúng tuyn */ #include #include #include struct TS { char ht[20]; float t,l,h,td; } ; void ints(const TS &ts) { cout > ts[i].t >> ts[i].l >> ts[i].h ; ts[i].td = ts[i].t + ts[i].l + ts[i].h ; } 30
  31. } // Hoán v hai bin cu trúc, dùng ñi tham chiu void hvts(TS &ts1, TS &ts2) { TS tg=ts1; ts1=ts2; ts2=tg; } void sapxep(TS *ts,int n) { for (int i=1;i > n ; nhapsl(ts,n); sapxep(ts,n) ; float dc; cout > dc; cout = dc) ints(ts[i]); else break; getch(); } § 3. Hµm tr¶ vÒ c¸c tham chiÕu Hm cã thÓ cã kiÓu tham chiÕu v tr¶ vÒ gi¸ trÞ tham chiÕu. Khi ®ã cã thÓ dïng hm ®Ó truy nhËp ®Õn mét biÕn hoÆc mét phÇn tö m¶ng no ®ã. D−íi ®©y l mét sè vÝ dô. VÝ dô 1 tr×nh bÇy mét hm tr¶ vÒ mét tham chiÕu ®Õn mét biÕn ton bé. Do ®ã cã thÓ dïng hm ®Ó truy nhËp ®Õn biÕn ny. 31
  32. #include int z ; // BiÕn ton bé int &f() // Hm tr¶ vÒ mét bÝ danh cña biÕn ton bé z { return z; } void main(void) { f()=50; cout #include struct TS { char ht[25]; float t,l,h,td; }; TS ts; TS &f() { return ts; } void main() { TS &h=f(); // h tham chiÕu ®Õn biÕn ts cout > h.t >> h.l >> h.h ; h.td = h.t + h.l + h.h ; cout << "\n Ho ten: " << ts.ht; cout << "\n Tong diem: " << ts.td; getch(); 32
  33. § 3. HÀM TR V CÁC THAM CHIU Hàm có th có kiu tham chiu và tr v giá tr tham chiu. Khi ñó có th dùng hàm ñ truy nhp ñn mt bin hoc mt phn t mng nào ñó. Dưi ñây là mt s ví d. Ví d 1 trình by mt hàm tr v mt tham chiu ñn mt bin toàn b. Do ñó có th dùng hàm ñ truy nhp ñn bin này. #include int z ; // Bin toàn b int &f() // Hàm tr v mt bí danh ca bin toàn b z { return z; } void main(void) { f()=50; cout #include struct TS { char ht[25]; float t,l,h,td; }; TS ts; TS &f() { return ts; } void main() { TS &h=f(); // h tham chiu ñn bin ts cout << "\n Ho ten: " ; 33
  34. cin.get(h.ht,25) ; cout > h.t >> h.l >> h.h ; h.td = h.t + h.l + h.h ; cout #include #include struct TS { char ht[25]; float t,l,h,td; }; TS *ts; void cap_phat_bo_nho_nhapsl(int n) { ts = new TS[n+1] ; if (ts==NULL) { cout << "Loi cap phat bo nho " ; exit(1); } for (int i=1;i<=n;++i) { TS &h=ts[i]; cout << "\nThi sinh thu " << i ; cout << "\n Ho ten: " ; cin.ignore(1); cin.get(h.ht,25) ; cout << "Cac diem toan, ly, hoa: "; 34
  35. cin >> h.t >> h.l >> h.h ; h.td = h.t + h.l + h.h ; } } TS &f(int i, int n) // Cho bi danh ts[i] { if (i n) { cout > n; cap_phat_bo_nho_nhapsl(n); while (1) { cout > i; TS &h=f(i,n); cout << "\n Ho ten: " << h.ht; cout << "\n Tong diem: " << h.td; } } § 4. ðI CÓ GIÁ TR MC ðNH 4.1. Th nào là ñi có giá tr mc ñnh Thông thưng s tham s trong li gi hàm phi bng s ñi ca hàm. Mi ñi s ñưc khi gán giá tr theo tham s tương ng ca nó. Trong C ++ cho phép to giá tr mc ñnh cho các ñi. Các ñi này có th có hoc không có tham s tương ng trong li gi hàm. Khi không có tham s tương ng, ñi ñưc khi gán bi giá tr mc ñnh. Ví d hàm delay vi ñi s mc ñnh ñưc vit theo mt trong 2 cách sau: Cách 1 (Không khai báo nguyên mu): void delay(int n=1000) 35
  36. { for (int i=0 ; i<n ; ++i) ; } Cách 2 (Có khai báo nguyên mu): void delay(int n=1000) ; void delay(int n) { for (int i=0 ; i<n ; ++i) ; } Cách dùng: + Cung cp giá tr cho ñi n (Có tham s trong li gi hàm) delay(5000) ; // ði n = 5000 + S dng giá tr mc ñnh ca ñi (Không có tham s trong li gi) delay() ; // ði n = 1000 4.2. Quy tc xây dng hàm vi ñi mc ñnh + Các ñi mc ñnh cn phi là các ñi cui cùng tính t trái sang phi. Gi s có 5 ñi theo th t t trái sang phi là: d1, d2, d3, d4, d5 Khi ñó (các ví d ñúng): nu mt ñi mc ñnh thì phi là d5 nu hai ñi mc ñnh thì phi là d4, d5 nu ba ñi mc ñnh thì phi là d3, d4, d5 Các ví d sai: d3 và d5 mc ñnh (ch ñúng khi d4 cũng phi mc ñnh) d3 và d4 mc ñnh (ch ñúng khi d5 cũng phi mc ñnh) + Khi xây dng hàm, nu s dng khai báo nguyên mu, thì các ñi mc ñnh cn ñưc khi gán ngay trong nguyên mu, ví d: // Khi gán giá tr cho 3 ñi mc ñnh d3, d4 và d5) void f(int d1, float d2, char *d3=”HA NOI”, int d4 = 100, double d5=3.14) ; void f(int d1, float d2, char *d3, int d4, double d5) { // Các câu lnh trong thân hàm 36
  37. } Không ñưc khi gán li cho các ñi mc ñnh trong dòng ñu ca ñnh nghĩa hàm. Nu vi phm ñiu này thì Chương trình dch s thông báo li. + Khi xây dng hàm, nu không khai báo nguyên mu, thì các ñi mc ñnh ñưc khi gán trong dòng ñu ca ñnh nghĩa hàm, ví d: // Khi gán giá tr cho 3 ñi mc ñnh d3, d4 và d5) void f(int d1, float d2, char *d3=”HA NOI”, int d4 = 100, double d5=3.14) { // Các câu lnh trong thân hàm } + Có th dùng các hng, các bin toàn b, các hàm ñ khi gán cho ñi mc ñnh, ví d: int MAX = 10000; void f(int n, int m = MAX, int xmax = getmaxx(), int ymax = getmaxy() ) ; 4.3. Cách s dng hàm có ñi mc ñnh Li gi hàm cn vit theo quy ñnh: Các tham s thiu vng trong li gi hàm phi tương ng vi các ñi mc ñnh cui cùng (tính t trái sang phi). Nói cách khác: ðã dùng giá tr mc ñnh cho mt ñi (tt nhiên phi là ñi mc ñnh) thì cũng phi s dng giá tr mc ñnh cho các ñi còn li. Ví d vi hàm có ba ñi mc ñnh: void f(int d1, float d2, char *d3=”HA NOI”, int d4 = 100, double d5=3.14) ; Thì các li gi sau là ñúng: f(3,3.4,”ABC”,10,1.0) ; // ðy ñ tham s f(3,3.4,”ABC”) ; // Thiu 2 tham s cui f(3,3.4) ; // Thiu 3 tham s cui Các li gi sau là sai: f(3) ; // Thiu tham s cho ñi không mc ñnh d2 f(3,3.4, ,10) ; // ðã dùng giá tr mc ñnh cho d3, thì cũng // phi dùng giá tr mc ñnh cho d4 và d5 4.4. Các ví d 37
  38. Ví d hàm ht trong chương trình sau dùng ñ hin th chui ký t dc trên n dòng màn hình. Các ñi dc và n ñu có giá tr mc ñnh. #include void ht(char *dc="HA NOI",int n=10) ; void main() { ht(); // In dòng ch “HA NOI” trên 10 dòng ht("ABC",3); // In dòng ch “ABC” trên 3 dòng ht("DEF"); // In dòng ch “DEF” trên 10 dòng } void ht(char *dc , int n ) { for (int i=0; i #include void hiendc(char *str, int x = getmaxx()/2, int y = getmaxy()/2, int m= RED); void main() { int mh=0, mode=0; initgraph(&mh, &mode,""); setbkcolor(BLUE); hiendc("HELLO"); // HELLO mu ñ gia màn hình hiendc("CHUC MUNG",1,1); // hin CHUC MUNG mu ñ ti v trí (1,1) hiendc("XIN CHAO",1,400,YELLOW); // hin XIN CHAO mu vàng ti // v trí (1,400) getch(); } void hiendc(char *str, int x,int y, int m) { int mau_ht = getcolor(); // Luu mau hien tai setcolor(m); 38
  39. outtextxy(x,y,str) ; setcolor(mau_ht); // Khoi phuc mau hien tai } § 5. CÁC HÀM TRC TUYN 5.1. Ưu, nhưc ñim ca hàm Vic t chc chương trình thành các hàm có 2 ưu ñim rõ rt : + Th nht là chia chương trình thành các ñơn v ñc lp, làm cho chương trình ñưc t chc mt cách khoa hc d kim soát d phát hin li, d phát trin, m rng. + Th hai là gim ñưc kích thưc chương trình, vì mi ñon chương trình thc hin nhim v ca hàm ñưc thay bng mt li gi hàm. Tuy nhiên cách t chc thành các hàm cũng có nhưc ñim là làm chm tc ñ chương trình do phi thc hin mt s thao tác có tính th tc mi khi gi hàm như: Cp phát vùng nh cho các ñi và bin cc b, truyn d liu ca các tham s cho các ñi, gii phóng vùng nh trưc khi thoát khi hàm. Các hàm trc tuyn (inline functions) trong C ++ giúp cho chương trình vn có th t chc thành các hàm nhưng khc phc ñưc nhưc ñim nói trên. 5.2. Xây dng hàm trc tuyn ð bin mt hàm thành trc tuyn ta vit thêm t khoá inline vào trưc khai báo nguyên mu hàm. Nu không dùng nguyên mu thì vit t khoá inline trưc dòng ñu tiên ca ñnh nghĩa hàm. Ví d: inline float f(int n, float x); // nguyên mu float f(int n, float x) { // Các câu lnh trong thân hàm } hoc (không dùng nguyên mu): inline float f(int n, float x) { // Các câu lnh trong thân hàm } 5.3. Cách biên dch hàm trc tuyn 39
  40. Trình biên dch x lý các hàm inline như các macro (ñưc ñnh nghĩa trong lnh #define), nghĩa là nó s thay mi li gi hàm bng mt ñon chương trình thc hin nhim v ca hàm. Cách này làm cho chương trình dài ra, nhưng tc ñ chương trình tăng lên do không phi thc hin các thao tác có tính th tc khi gi hàm. Phương án dùng hàm trc tuyn rút ngn ñưc thi gian chy máy nhưng li làm tăng khi lưng b nh chương trình (nht là ñi vi các hàm trc tuyn có nhiu câu lnh). Vì vy ch nên dùng phương án trc tuyn ñi vi các hàm nh. Chú ý: Dùng macro và hàm trc tuyn ñu dn ñn hiu qu tương t nhau, tuy nhiên ngưi ta thích dùng hàm trc tuyn hơn, vì cách này ñm bo tính cu trúc ca chương trình, d s dng và tránh ñưc các sai sót lt vt thưng gp khi dùng #define (như thiu các du ngoc, du chm phy) 5.4. S hn ch ca Trình biên dch Không phi khi gp t khoá inline là Trình biên dch cũng nht thit phi x lý hàm theo kiu trc tuyn. T khoá inline ch là mt s gi ý cho Trình biên dch ch không phi là mt mnh lnh bt buc. Có mt s hàm mà các Trình biên dch thưng không x lý theo cách inline như các hàm cha bin static, hàm cha các lnh lp, lnh goto hoc lnh switch, hàm ñ quy. Trong các trưng hp này t khoá inline s b b qua. Thm chí t khoá inline vn b b qua ngay c ñi vi các hàm không có nhng hn ch nêu trên nu như Trình biên dch thy cn thit (ví d ñã có quá nhiu hàm inline làm cho b nh chương trình quá ln) Ví d: Chương trình sau s dng hàm inline tính chu vi và din tích ca hình ch nht: Cách 1: Không khai báo nguyên mu. Khi ñó hàm dtcvhcn phi ñưc xây dng trên hàm main. #include inline void dtcvhcn(int a, int b, int &dt, int &cv) { dt=a*b; cv=2*(a+b); } void main() { int a[20],b[20],cv[20],dt[20],n; cout > n; for (int i=1;i<=n;++i) { cout << "\nNhap 2 canh cua hinh chu nhat thu " <<i<< ": "; 40
  41. cin >> a[i] >> b[i] ; dtcvhcn(a[i],b[i],dt[i],cv[i]); } for (i=1;i inline void dtcvhcn(int a, int b, int &dt, int &cv) ; void main() { int a[20],b[20],cv[20],dt[20],n; cout > n; for (int i=1;i > a[i] >> b[i] ; dtcvhcn(a[i],b[i],dt[i],cv[i]); } for (i=1;i<=n;++i) { cout << "\n Hinh chu nhat thu " << i << " : "; cout << "\nDo dai 2 canh= " << a[i] << " va " << b[i] ; cout << "\nDien tich= " << dt[i] ; cout << "\nChu vi= " << cv[i] ; } } void dtcvhcn(int a, int b, int &dt, int &cv) { dt=a*b; 41
  42. cv=2*(a+b); } Chú ý: Không ñưc ñt inline trưc ñnh nghĩa hàm. Trong chương trình trên ñây nu ñt inline trưc ñnh nghĩa hàm thì hu qu như sau: Chương trình vn dch thông, nhưng khi chy thì chương trình b qun, không thoát ñưc. § 6. ðNH NGHĨA CHNG CÁC HÀM 6.1. Khái nim v ñnh nghĩa chng (overloading) ðnh nghĩa chng hay còn gi s ti bi các hàm là vic dùng cùng mt tên ñ ñnh nghĩa các hàm khác nhau. ðây là mt m rng rt có ý nghĩa ca C ++ . Như ñã bit, trong C và các ngôn ng khác (PASCAL, ) mi hàm ñu phi có mt tên phân bit. ðôi khi ñây là mt s hn ch ln, vì phi dùng nhiu hàm khác nhau ñ thc hin cùng mt loi công vic. Ví d ñ ly giá tr tuyt ñi trong C cn dùng ti 3 hàm khác nhau: int abs(int i); // Ly giá tr tuyt ñi giá tr kiu int longt labs(longt l); // Ly giá tr tuyt ñi giá tr kiu long double fabs(double d); // Ly giá tr tuyt ñi giá tr kiu double Nh kh năng ñnh nghĩa chng, trong C ++ có th dùng chung mt tên cho c 3 hàm trên như sau: int abs(int i) ; // Ly giá tr tuyt ñi giá tr kiu int longt abs(longt l) ; // Ly giá tr tuyt ñi giá tr kiu long double abs(double d) ; // Ly giá tr tuyt ñi giá tr kiu double 6.2. Yêu cu ñi vi các hàm ñnh nghĩa chng Khi dùng cùng mt tên ñ ñnh nghĩa nhiu hàm, Trình biên dch C ++ s da vào s khác nhau v tp ñi ca các hàm này ñ ñi tên các hàm. Như vy, sau khi biên dch mi hàm s có mt tên khác nhau. T ñó cho thy: các hàm ñưc ñnh nghĩa trùng tên phi có tp ñi khác nhau (v s lưng hoc kiu). Nu hai hàm hoàn toàn trùng tên và trùng ñi thì Trình biên dch s không có cách nào phân bit ñưc. Ngay c trong trưng hp hai hàm này có kiu khác nhau thì Trình biên dch vn báo li. 6.3. S dng các hàm ñnh nghĩa chng Khi gp mt li gi, Trình biên dch s căn c vào s lưng và kiu ca các tham s ñ gi hàm có ñúng tên và ñúng b ñi s tương ng. Ví d: abs(123); // Tham s kiu int, gi hàm int abs(int i) ; abs(123L); // Tham s kiu long, gi hàm long abs(long l); abs(3.14); // Tham s kiu double, gi hàm double abs(double d); 42
  43. Khi không có hàm nào có b ñi cùng kiu vi b tham s (trong li gi) thì Trình biên dch s chn hàm nào có b ñi gn kiu nht (phép chuyn kiu d dàng nht). Ví d: abs(‘A’) ; // Tham s kiu char, gi hàm int abs(int i) ; abs(3.14F); // Tham s kiu float, gi hàm double abs(double d); Như ñã nói trên, khi xây dng cũng như s dng các hàm trùng tên, Trình biên dch C ++ ñã phi suy ñoán và gii quyt nhiu trưng hp khá nhp nhng. Vì vy không nên lm dng quá ñáng kh năng ñnh nghĩa chng, vì ñiu ñó làm cho chương trình khó kim soát và d dn ñn sai sót. Vic ñnh nghĩa chng s hiu qu hơn nu ñưc s dng theo các qui tc sau: + Ch nên ñnh nghĩa chng các hàm thc hin nhng công vic như nhau nhưng trên các ñi tưng có kiu khác nhau. Ví d trong chương trình cn xây dng các hàm: cng hai ma trn vuông kiu double, cng hai ma trn vuông kiu int, cng hai ma trân ch nht kiu double, cng hai ma trn ch nht kiu int, thì bn hàm trên nên ñnh nghĩa chng (ñt cùng tên). + Nên dùng các phép chuyn kiu ñ b tham s trong li gi hoàn toàn trùng kiu vi b ñi s ca mt hàm ñưc ñnh nghĩa chng. Vì như th mi tránh ñưc s nhp nhng cho Trình biên dch và do ñó nó s chn ñúng hàm cn gi. 6.4. Ly ña ch các hàm trùng tên Gi s có bn hàm ñu có tên là tinh_max ñưc khai báo như sau: int tinh_max(int a, int b, int c) ; // Max ca ba s nguyên double tinh_max(double a, double b, double c); // Max ca ba s thc int tinh_max(int *a, int n) ; // Max ca mt dy s nguyên double tinh_max(double *a, int n) ; //Max ca mt dy s thc Vn ñ ñt ra là làm th nào ly ñưc ña ch ca mi hàm. Câu tr li như sau: ð ly ña ch ca mt hàm, ta khai báo mt con tr hàm có kiu và b ñi như hàm cn ly ña ch. Sau ñó gán tên hàm cho con tr hàm. Ví d: int (*f1)(int , int, int ); f1 = tinh_max ; // Ly ña ch ca hàm th nht double (*f2)(double , double, double); f2 = tinh_max ; // Ly ña ch ca hàm th hai int (*f3)(int *, int ); f3 = tinh_max ; // Ly ña ch ca hàm th ba double (*f4)(double *, int ); f4 = tinh_max ; // Ly ña ch ca hàm th tư Ví d: Chương trình gii bài toán tìm max ca mt dy s nguyên và max ca mt dy s thc. Trong chươmg trình có sáu hàm. Hai hàm dùng ñ nhp dy s nguyên và dy s thc có tên chung là nhapds. Bn hàm: tính max hai s nguyên, tính max 43
  44. hai s thc, tính max ca dy s nguyên, tính max ca dy s thc ñưc ñt chung mt tên là max. #include #include void nhapds(int *x, int n); void nhapds(double *x, int n); int max(int x, int y); double max(double x, double y); int max(int *x, int n); double max(double *x, int n); void nhapds(int *x, int n) { for (int i=1;i > x[i] ; } } void nhapds(double *x, int n) { for (int i=1;i > x[i] ; } } int max(int x, int y) { return x>y?x:y ; } double max(double x, double y) { return x>y?x:y ; } int max(int *x, int n) { 44
  45. int s=x[1]; for (int i=2;i > ni ; cout > nd ; cout << "Nhap day so thuc\n " ; nhapds(x,nd); maxi = max(a,ni); maxd = max(x,nd); cout << "\nMax cua day nguyen = " << maxi ; cout << "\nMax cua day thuc = " << maxd ; } § 7. ðNH NGHĨA CHNG CÁC TOÁN T 7.1. Các phép toán trên các kiu d liu chun Trong C và C ++ có khá nhiu các phép toán dùng ñ thc hin các thao tác trên các kiu d liu chun. Ví d các phép s hc ( + , , * , / ) áp dng cho các kiu d liu nguyên, thc, phép ly phn dư % áp dng ñi vi kiu nguyên. 7.2. Thc hin các phép toán trên các kiu d liu không chun 45
  46. Vic thc hin các phép toán trên các ñi tưng t ñnh nghĩa (như mng, cu trúc) là nhu cu bt buc trong thc t. Chng hn cn thc hin các phép s hc trên s phc, trên phân s, trên ña thc, trên véc tơ, trên ma trn. ð ñáp ng yêu cu này, ta s dng các hàm trong C. Ví d sau ñây là mt chương trình C gm các hàm nhp phân s, in phân s và thc hin các phép cng tr nhân chia phân s. Chương trình s nhp 5 phân s: p, q, z, u, v và tính phân s s theo công thc: s = (p – q*z)/(u + v) #include #include typedef struct { int a,b; } PS; void nhap(PS *p); void in(PS p); int uscln(int x, int y); PS rutgon(PS p); PS cong(PS p1, PS p2); PS tru(PS p1, PS p2); PS nhan(PS p1, PS p2); PS chia(PS p1, PS p2); void nhap(PS *p) { int t, m; printf("\nTu va mau: "); scanf("%d%d", &t, &m); p>a = t; p>b = m; } void in(PS p) { printf(" %d/%d",p.a,p.b); } int uscln(int x, int y) { x=abs(x); y=abs(y); if (x*y==0) return 1; while (x!=y) 46
  47. if (x>y) x=y; else y=x; return x; } PS rutgon(PS p) { PS q; int x; x=uscln(p.a,p.b); q.a = p.a / x ; q.b = p.b / x ; return q; } PS cong(PS p1, PS p2) { PS q; q.a = p1.a*p2.b + p2.a*p1.b; q.b = p1.b * p2.b ; return rutgon(q); } PS tru(PS p1, PS p2) { PS q; q.a = p1.a*p2.b p2.a*p1.b; q.b = p1.b * p2.b ; return rutgon(q); } PS nhan(PS p1, PS p2) { PS q; q.a = p1.a * p2.a ; q.b = p1.b * p2.b ; return rutgon(q); } PS chia(PS p1, PS p2) { 47
  48. PS q; q.a = p1.a * p2.b ; q.b = p1.b * p2.a ; return rutgon(q); } void main() { PS p, q, z, u, v ; PS tu,mau, s; printf("\n Nhap phan so p: "); nhap(&p); printf("\n Nhap phan so q: ");nhap(&q); printf("\n Nhap phan so z: ");nhap(&z); printf("\n Nhap phan so u: ");nhap(&u); printf("\n Nhap phan so v: ");nhap(&v); tu = nhan(q,z); tu = tru(p,tu) ; mau = cong(u,v) ; s = chia(tu,mau); printf(“\n Phan so s = “); in(s); } Nhn xét: Vic s dng các hàm ñ thc hin các phép tính không ñưc t nhiên và t ra dài dòng. Câu hi ñt ra là có cách nào ñ ch cn vit ñúng công thc toán hc, mà vn nhn ñưc kt qu mong mun hay không? Trong C ++ có th ñáp ng ñưc mong mun này bng cách vn có th s dng các phép toán chun ca nó cho các kiu d liu t ñnh nghĩa (mng, cu trúc, ). Nói cách khác C ++ cho phép dùng các phép toán ñ ñnh nghĩa các hàm, mà ta thưng gi là ñnh nghĩa chng các toán t (hay còn gi là s ti bi các toán t). 7.3. Cách ñnh nghĩa chng các toán t Tên hàm toán t: Gm t khoá operator và tên phép toán, ví d: operator+ (ñnh nghĩa chng phép +) operator (ñnh nghĩa chng phép ) Các ñi ca hàm toán t: 48
  49. + Vi các phép toán có hai toán hng thì hàm toán t cn có hai ñi. ði th nht ng vi toán hng th nht, ñi th hai ng vi toán hng th hai. Do vy, vi các phép toán không giao hoán (như phép ) thì th t ñi là rt quan trng. Ví d các hàm toán t cng , tr phân s ñưc khai báo như sau: struct PS { int a; // T s int b; // Mu s } ; PS operator+(PS p1, PS p2); // p1 + p2 PS operator(PS p1, PS p2); // p1 p2 PS operator*(PS p1, PS p2); // p1 * p2 PS operator/(PS p1, PS p2); // p1 / p2 Ví d chương trình ñnh nghĩa và s dng mt toán t nhân hai phân s. #include typedef struct { int x,y; } PS; PS operator*(PS p1, PS p2) { PS p; p.x=p1.x * p2.x; p.y=p1.y * p2.y; return p; } void main() { PS ps1, ps2, ps; cout >ps1.x>>ps1.y; cout >ps2.x>>ps2.y; ps= ps1*ps2; cout<<"Phan so 3: "<<ps.x<<"/"<<ps.y; } + Vi các phép toán có mt toán hng thì hàm toán t có mt ñi. Ví d hàm toán t ñi du ma trn (ñi du tt c các phn t ca ma trn) ñưc khai báo như sau: struct MT { double a[20][20] ; // Mng cha các phn t ma trn int m ; // S hàng ma trn 49
  50. int n ; // S ct ma trân } ; MT operator(MT x) ; Thân ca hàm toán t: Vit như thân ca hàm thông thưng. Ví d hàm ñi du ma trn có th ñưc ñnh nghĩa như sau: struct MT { double a[20][20] ; // Mng cha các phn t ma trn int m ; // S hàng ma trn int n ; // S ct ma trân } ; MT operator(MT x) { MT y; for (int i=1; i<= m ;++i) for (int j=1; j<= n ;++j) y[i][j] = x[i][j] ; return y; } 7.4. Cách dùng hàm toán t Có hai cách dùng: Cách 1: Dùng như mt hàm thông thưng bng cách vit li gi. Ví d: PS p, q, u, v ; u = operator+(p, q) ; // u = p + q v = operator(p, q) ; // v = p q Cách 2: Dùng như phép toán ca C ++ . Ví d: PS p, q, u, v ; u = p + q ; // u = p + q v = p q ; // v = p q Chú ý: Khi dùng các hàm toán t như phép toán ca C ++ ta có th kt hp nhiu phép toán ñ vit các công thc phc tp mt cách gn gàng. Cũng cho phép dùng du ngoc tròn ñ quy ñnh th t thc hin các phép tính. Th t ưu tiên ca các 50
  51. phép tính vn tuân theo các quy tc ban ñu ca C ++ . Chng hn các phép * và / có th ưu tiên cao hơn so vi các phép + và . Ví d: PS p, q, u, v, s1, s2 ; s1 = p*q u/v ; // s1 = (p*q) s2 = (p q)/(u + v) ; // s2 = (p q)/(u + v) BÀI TP CHƯƠNG 2 Bài 1. Xác ñnh kt qu ca mi chương trình sau: /* Chương trình 1 */ #include void doi(int *a, int b); void main() { int x, y; doi(&x, y=2); printf("%d %d",x, y); } void doi(int *a, int b) { *a=b; *a+=b++; } /* Chương trình 2 */ #include int x=2; int swap(int &x, int &y); void main() { int x=10; int y=12; swap(x,y); printf("Sau hoan vi:\n x=%d y=%d",x, y); } int swap(int x, int y) 51
  52. { int tam=x; x=y; y=tam; } Bài 2. Vit chương trình nhp hai dãy s ñã ñưc sp xp tăng dn, sau ñó ghép hai dãy s trên thành mt dãy cũng ñưc sp tăng dn. Bài 3. Vit chương trình ñnh nghĩa mt cu trúc phân s và các phép toán cng (+), tr (), nhân (*), chia (/) hai phân s. Nhp các phân s p, q, z, u, v. Tính giá tr biu thc (p – q*z)/(u + v). 52
  53. CHƯƠNG 3 LP VÀ ðI TƯNG Lp (class) là khái nim trung tâm trong lp trình hưng ñi tưng, nó là s m rng ca khái nim cu trúc (struct) ca C. Ngoài các thành phn d liu (ging như cu trúc), lp còn cha các thành phn hàm, còn gi là phương thc (method) hay hàm thành viên (member function). Cũng ging như cu trúc, lp có th ñưc xem như mt kiu d liu. Vì vy lp còn ñưc gi là kiu ñi tưng và do ñó có th dùng ñ khai báo các bin, mng ñi tưng (như th dùng kiu int ñ khai báo các bin mng nguyên). Như vy t mt lp có th to ra (bng cách khai báo) nhiu ñi tưng (object) khác nhau. Mi ñi tưng có vùng nh riêng ca mình. Chương này s trình by cách ñnh nghĩa lp, cách xây dng các phương thc, gii thích v phm vi truy nhp, s dng các thành phn ca lp, cách khai báo bin, mng cu trúc, li gi ti các phương thc, § 1. ðNH NGHĨA LP 1.1. ðnh nghĩa lp Lp ñưc ñnh nghĩa theo mu: class tên_lp { // Khai báo các thành phn d liu (thuc tính) // Khai báo các phương thc } ; // ðnh nghĩa (xây dng) các phương thc Chú ý: Thuc tính ca lp có th là các bin, mng, con tr có kiu chun (int, float, char, char*, long, ) hoc kiu ngoài chun ñã ñnh nghĩa trưc (cu trúc, hp, lp, ) . Thuc tính ca lp không th có kiu ca chính lp ñó, nhưng có th là kiu con tr lp này, ví d: class A { A x ; // Không cho phép, vì x có kiu lp A A *p ; // Cho phép , vì p là con tr kiu lp A }; 1.2. Các thành phn ca lp Khi báo các thành phn ca lp (thuc tính và phương thc) có th dùng các t khoá private và public ñ quy ñnh phm vi s dng ca các thành phn. Nu không 53
  54. quy ñnh c th (không dùng các t khoá private hay public) thì C ++ mc ñnh hiu ñó là private. Các thành phn private (riêng) ch ñưc s dng bên trong lp (trong thân ca các phương thc ca lp). Các hàm không phi là phương thc ca lp không ñưc phép s dng các thành phn này. Các thành phn public (chung) ñưc phép s dng c bên trong và bên ngoài lp. Các thành phn d liu thưng khai báo là private (nhưng không bt buc) ñ bo ñm tính giu kín, bo v an toàn d liu ca lp, không cho phép các hàm bên ngoài xâm nhp vào d liu ca lp. Các phương thc thưng khai báo là public ñ chúng có th ñưc gi ti (s dng) t các hàm khác trong chương trình. Các phương thc có th ñưc xây dng bên ngoài hoc bên trong ñnh nghĩa lp. Thông thưng, các phương thc ngn ñưc vit bên trong ñnh nghĩa lp, còn các phương thc dài thì vit bên ngoài ñnh nghĩa lp. Trong thân phương thc ca mt lp (gi s lp A) có th s dng: + Các thuc tính ca lp A + Các phương thc ca lp A + Các hàm t lp trong chương trình. Vì phm vi s dng ca hàm là toàn chương trình. Giá tr tr v ca phương thc có th có kiu bt kỳ (chun và ngoài chun) Ví d sau s minh ho các ñiu nói trên. Chúng ta s ñnh nghĩa lp ñ mô t và x lý các ñim trên màn hình ñ ho. Lp ñưc ñt tên là DIEM. + Các thuc tính ca lp gm: int x ; // hoành ñ (ct) int y ; // tung ñ (hàng) int m ; // mu + Các phương thc: Nhp d liu mt ñim Hin th mt ñim n mt ñim Lp ñim ñưc xây dng như sau: class DIEM { int x, y, m ; public: void nhapsl() ; void hien() ; void an() { 54
  55. putpixel(x, y, getbkcolor()); } } ; void DIEM::nhap() { cout > x >> y ; cout > m ; } void DIEM::hien() { int mau_ht ; mau_ht = getcolor(); putpixel(x, y, m); setcolor(mau_ht); } Qua ví d trên có th rút ra mt s ñiu cn nh sau: + Trong c ba phương thc (dù vit trong hay vit ngoài ñnh nghĩa lp) ñu ñưc phép truy nhp ñn các thuc tính x, y và m ca lp. + Các phương thc vit bên trong ñnh nghĩa lp (như phương thc an) ñưc vit như mt hàm thông thưng. + Khi xây dng các phương thc bên ngoài lp (như các phương thc nhap, hien) cn dùng thêm tên lp và toán t phm vi :: ñt ngay trưc tên phương thc ñ quy ñnh rõ ñây là phương thc ca lp nào. § 2. BIN, MNG ðI TƯNG 2.1. Khai báo bin, mng ñi tưng Mt lp (sau khi ñnh nghĩa) có th xem như mt kiu ñi tưng và có th dùng ñ khai báo các bin, mng ñi tưng. Cách khai báo bin, mng ñi tưng cũng ging như khai báo bin, mng các kiu khác (như int, float, cu trúc, hp, ), theo mu sau: Tên_lp danh sách ñi ; Tên_lp danh sách mng ; Ví d s dng lp DIEM §1, có th khai báo các bin, mng DIEM như sau: 55
  56. DIEM d1, d2, d3 ; // Khai báo 3 bin ñi tưng d1, d2, d3 DIEM d[20] ; // Khai báo mng ñi tưng d gm 20 phn t Mi ñi tưng sau khi khai báo s ñưc cp phát mt vùng nh riêng ñ cha các thuc tính ca chúng. Chú ý rng s không có vùng nh riêng ñ cha các phương thc cho mi ñi tưng. Các phương thc s ñưc s dng chung cho tt c các ñi tưng cùng lp. Như vy v b nh ñưc cp phát thì ñi tưng ging cu trúc. Trong trưng hp này: sizeof(d1) = sizeof(d2) = sizeof(d3) = 3*sizeof(int) = 6 sizeof(d) = 20*6 = 120 2.2. Thuc tính ca ñi tưng Trong ví d trên, mi ñi tưng d1, d2, d3 và mi phn t d[i] ñu có ba thuc tính là x, y, m. Mi thuc tính ñu thuc v mt ñi tưng, vì vy không th vit tên thuc mt cách riêng r mà bao gi cũng phi có tên ñi tưng ñi kèm, ging như cách vit trong cu trúc ca C. Nói cách khác, cách vit thuc tính ca ñi tưng như sau: Tên_ñi_tưng.Tên_thuc_tính Vi các ñi tưng d1, d2, d3 và mng d, có th vit như sau: d1.x // Thuc tính x ca ñi tưng d1 d2.x // Thuc tính x ca ñi tưng d2 d3.y // Thuc tính y ca ñi tưng d3 d[2].m // Thuc tính m ca phn t d[2] d1.x = 100 ; // Gán 100 cho d1.x d2.y = d1.x; // Gán d1.x cho d2.y 2.3. S dng các phương thc Cũng ging như hàm, mt phương thc ñưc s dng thông qua li gi. Tuy nhiên trong li gi phương thc bao gi cũng phi có tên ñi tưng ñ ch rõ phương thc thc hin trên các thuc tính ca ñi tưng nào. Ví d li gi: d1.nhapsl(); s thc hin nhp s liu vào các thành phn d1.x, d1.y và d1.m Câu lnh: d[3].nhapsl() ; s thc hin nhp s liu vào các thành phn d[3].x, d[3].y và d[3].m Chúng ta s minh ho các ñiu nói trên bng mt chương trình ñơn gin s dng lp DIEM ñ nhp ba ñim, hin ri n các ñim va nhp. #include #include #include 56
  57. class DIEM { int x, y, m ; public: void nhapsl(); void an() { putpixel(x,y,getbkcolor()); } void hien(); }; void DIEM::nhapsl() { cout > x >> y ; cout > m ; } void DIEM::hien() { int mau_ht; mau_ht = getcolor() ; putpixel(x,y,m); setcolor(mau_ht); } void kd_do_hoa() // Khi ñng ñ ha { int mh, mode ; mh=mode=0; initgraph(&mh, &mode, ""); } void main() { DIEM d1, d2, d3 ; d1.nhapsl(); d2.nhapsl(); 57
  58. d3.nhapsl(); kd_do_hoa(); setbkcolor(BLACK); d1.hien(); d2.hien(); d3.hien(); getch(); d1.an(); d2.an(); d3.an(); getch(); closegraph(); } § 3. CON TR ðI TƯNG Con tr ñi tưng dùng ñ cha ña ch ca bin, mng ñi tưng. Nó ñưc khai báo như sau: Tên_lp *Tên_con_tr ; Ví d dùng lp DIEM có th khai báo: DIEM *p1 , *p2, *p3 ; // Khai báo 3 con tr p1, p2, p3 DIEM d1, d2 ; // Khai báo 2 ñi tưng d1, d2 DIEM d[20] ; // Khai báo mng ñi tưng và có th thc hin các câu lnh: p1 = &d2 ; // p1 cha ña ch ca d2 , hay p1 tr ti d2 p2 = d ; // p2 tr ti ñu mng d p3 = new DIEM // To mt ñi tưng và cha ña ch ca nó vào p3 ð s dng thuc tính ca ñi tưng thông qua con tr, ta vit như sau: Tên_con_tr>Tên_thuc_tính Chú ý: Nu con tr cha ña ch ñu ca mng, có th dùng con tr như tên mng. Như vy sau khi thc hin các câu lnh trên thì: p1>x và d2.x là như nhau p2[i].y và d[i].y là như nhau Quy tc s dng thuc tính: ð s dng mt thuc tính ca ñi tưng ta phi dùng phép . hoc phép > . Trong chương trình, không cho phép vit tên thuc tính mt cách ñơn ñc mà phi ñi kèm tên ñi tưng hoc tên con tr theo các mu sau: 58
  59. Tên_ñi_tưng.Tên_thuc_tính Tên_con_tr>Tên_thuc_tính Tên_mng_ñi_tưng[ch_s].Tên_thuc_tính Tên_con_tr[ch_s].Tên_thuc_tính Chương trình dưi ñây cũng s dng lp DIEM ñ nhp mt dy ñim, hin th và n các ñim va nhp. Chương trình dùng mt con tr kiu DIEM và dùng toán t new ñ to ra mt dy ñi tưng. #include #include #include class DIEM { int x, y, m ; public: void nhapsl(); void an() { putpixel(x,y,getbkcolor()); } void hien(); }; void DIEM::nhapsl() { cout > x >> y ; cout > m ; } void DIEM::hien() { int mau_ht; mau_ht = getcolor() ; putpixel(x,y,m); setcolor(mau_ht); } 59
  60. void kd_do_hoa() { int mh, mode ; mh=mode=0; initgraph(&mh, &mode, ""); } void main() { DIEM *p; int i, n; cout > n; p = new DIEM[n+1]; for (i=1; i > x >> y ; cout > m ; } Rõ ràng trong phương thc này chúng ta s dng tên các thuc tính x, y và m mt cách ñơn ñc. ðiu này có v như mâu thun vi quy tc s dng thuc tính nêu 60
  61. trong mc trưc. Song s th là: C++ s dng con tr ñc bit this trong các phương thc. Các thuc tính vit trong phương thc ñưc hiu là thuc mt ñi tưng do con tr this tr ti. Phương thc nhapsl có th vit mt cách tưng minh như sau: void DIEM::nhapsl() { cout > this>x >> this>y ; cout > this>m ; } T góc ñ hàm s có th kt lun rng: Phương thc ca lp bao gi cũng có ít nht mt ñi là con tr this và nó luôn luôn là ñi ñu tiên ca phương thc. 4.2. Tham s ng vi ñi con tr this Xét mt li gi ti phương thc nhapsl: DIEM d1; d1.nhapsl() ; Trong trưng hp này tham s truyn cho con tr this chính là ña ch ca d1: this = &d1 Do ñó: this>x chính là d1.x this>y chính là d1.y this>m chính là d1.m *this chính là d1 Như vy câu lnh: d1.nhapsl() ; s nhp d liu cho các thuc tính ca ñi tưng d1. T ñó có th rút ra kt lun: Tham s truyn cho ñi con tr this chính là ña ch ca ñi tưng ñi kèm vi phương thc trong li gi phương thc. 4.3. Các ñi khác ca phương thc Ngoài ñi ñc bit this (ñi này không xut hin mt cách tưng minh), phương thc còn có các ñi khác ñưc khai báo như trong các hàm. ði ca phương thc có th có kiu bt kỳ (chun và ngoài chun). Ví d ñ xây dng phương thc v ñưng thng qua 2 ñim ta cn ñưa vào 3 ñi: Hai ñi là 2 bin kiu DIEM, ñi th ba kiu nguyên xác ñnh mã mu. Vì ñã có ñi ngm ñnh this là ñi th nht, nên ch cn khai báo thêm 2 ñi. Phương thc có th vit như sau: 61
  62. void DIEM::doan_thang(DIEM d2, int mau) { int mau_ht; mau_ht = getcolor(); setcolor(mau); line(this>x, this>y, d2.x, d2.y); setcolor(mau_ht); } Chương trình sau minh ho các phương thc có nhiu ñi. Ta vn dùng lp DIEM nhưng có mt s thay ñi: + B thuc tính m (mu) + B các phương thc hien và an + ðưa vào bn phương thc mi: ve_ doan_thang (V ñon thng qua 2 ñim) ve_tam_giac (V tam giác qua 3 ñim) do_dai (Tính ñ dài ca ñon thng qua 2 ñim) chu_vi (Tính chu vi tam giác qua 3 ñim) Chương trình còn minh ho: + Vic phương thc này s dng phương thc khác (phương thc ve_tam_giac s dng phương thc ve_doan_thang, phương thc chu_vi s dng phương thc do_dai) + S dng con tr this trong thân các phương thc ve_tam_giac và chu_vi Ni dung chương trình là nhp ba ñim, v tam giác có ñnh là ba ñim va nhp sau ñó tính chu vi tam giác. #include #include #include #include #include class DIEM { int x, y ; public: void nhapsl(); void ve_doan_thang(DIEM d2, int mau) ; void ve_tam_giac(DIEM d2, DIEM d3,int mau) ; double do_dai(DIEM d2) { 62
  63. DIEM d1 = *this ; return sqrt( pow(d1.x d2.x,2) + pow(d1.y d2.y,2) ) ; } double chu_vi(DIEM d2, DIEM d3); }; void DIEM::nhapsl() { cout > x >> y ; } void kd_do_hoa() { int mh, mode ; mh=mode=0; initgraph(&mh, &mode, ""); } void DIEM::ve_doan_thang(DIEM d2, int mau) { setcolor(mau); line(this>x,this>y,d2.x,d2.y); } void DIEM::ve_tam_giac(DIEM d2, DIEM d3,int mau) { (*this).ve_doan_thang(d2,mau); d2.ve_doan_thang(d3,mau); d3.ve_doan_thang(*this,mau); } double DIEM::chu_vi(DIEM d2, DIEM d3) { double s; s= (*this).do_dai(d2) + d2.do_dai(d3) + d3.do_dai(*this) ; return s; } void main() { DIEM d1, d2, d3; d1.nhapsl(); 63
  64. d2.nhapsl(); d3.nhapsl(); kd_do_hoa(); d1.ve_tam_giac(d2,d3,15); double s = d1.chu_vi(d2,d3); printf("Chu vi = %0.2f", s); getch(); closegraph(); } 4.4. Mt s nhn xét v ñi ca phương thc và li gi phương thc Quan sát nguyên mu phương thc: void ve_doan_thang(DIEM d2, int mau) ; Nhn thy phương thc có ba ñi: ði th nhât là mt ñi tưng DIEM do this tr ti ði th hai là ñi tưng DIEM d2 ði th ba là bin nguyên (mau) Ni dung phương thc là v mt ñon thng ñi qua các ñim *this và d2 theo mã mu mau. Xem thân ca phương thc s thy ñưc ni dung này: void DIEM::ve_doan_thang(DIEM d2, int mau) { setcolor(mau); line(this>x, this>y, d2.x, d2.y); } Tuy nhiên trong trưng hp này, vai trò ca this không cao lm, vì nó ñưc ñưa vào ch ct làm rõ ñi th nht. Trong thân phương thc có th b t khoá this vn ñưc. Vai trò ca this tr nên quan trng trong phương thc ve_tam_giac: void ve_tam_giac(DIEM d2, DIEM d3,int mau) ; Phương thc này có bn ñi là: this tr ti mt ñi tưng kiu DIEM d2 mt ñi tưng kiu DIEM d3 mt ñi tưng kiu DIEM mau mt bin nguyên Ni dung phương thc là v 3 cnh: cnh 1 ñi qua *this và d2 cnh 2 ñi qua d2 và d3 64
  65. cnh 3 ñi qua d3 và *this Các cnh trên ñưc v nh s dng phương thc ve_doan_thang: V cnh 1 dùng lnh: (*this).ve_doan_thang(d2,mau) ; V cnh 2 dùng lnh: d2.ve_doan_thang(d3,mau); V cnh 3 dùng lnh: d3.ve_doan_thang(*this,mau); Trong trưng này rõ ràng vai trò ca this rt quan trng. Nu không dùng nó thì công vic tr nên khó khăn, dài dòng và khó hiu hơn. Chúng ta hãy so sánh hai phương án: + Phương án dùng this trong phương thc ve_tam_giac: void DIEM::ve_tam_giac(DIEM d2, DIEM d3,int mau) { (*this).ve_doan_thang(d2,mau); d2.ve_doan_thang(d3,mau); d3.ve_doan_thang(*this,mau); } + Phương án không dùng this trong phương thc ve_tam_giac: void DIEM::ve_tam_giac(DIEM d2, DIEM d3,int mau) { DIEM d1; d1.x = x; d1.y = y; d1.ve_doan_thang(d2,mau); d2.ve_doan_thang(d3,mau); d3.ve_doan_thang(d1,mau); } 4.5. Các ví d Ví d 1 minh ho: + Thuc tính (thành phn d liu) ca lp có th là ñi tưng ca lp khác ñã ñnh nghĩa bên trên. + Phương thc có giá tr tr v kiu ñi tưng và con tr ñi tưng. Ni dung chương trình là nhp mt dy hình ch nht, sau ñó tìm hình ch nht có din tích ln nht và hình ch nht có chu vi ln nht. Chương trình ñưc t chc thành hai lp: + Lp HINH_CN gm: Các thuc tính: d và r (chiu dài và chiu rng) Các phương thc void nhapsl() ; // Nhp chiu dài, rng 65
  66. int dien_tich(); // Tính din tích int chu_vi() ; // Tính chu vi + Lp DAY_HINH_CN gm: Các thuc tính: int n ; //S hình ch nht ca dy HINH_CN *h; //Con tr ti dy ñi tưng ca lp HINH_CN Các phương thc: void nhapsl(); // Nhp mt dy hình ch nht HINH_CN hinh_dt_max() ; // Tr v hình ch nht có din tích max HINH_CN *hinh_cv_max() ; // Tr v con tr ti HCN có chu vi max #include #include class HINH_CN { int d, r; // chieu dai va chieu rong public: void nhapsl() { cout > d >> r ; } void in() { cout << "\nchieu dai = " << d ; cout << " chieu rong= " << r; } int dien_tich() { return d*r; } int chu_vi() { return 2*(d+r); } } ; class DAY_HINH_CN 66
  67. { int n; // So hinh ch nhat HINH_CN *h; public: void nhapsl(); HINH_CN hinh_dt_max() ; HINH_CN *hinh_cv_max() ; } ; void DAY_HINH_CN::nhapsl() { cout > n; h = new HINH_CN[n+1]; for (int i=1;i hdtmax.dien_tich() ) hdtmax = h[i]; return hdtmax; } HINH_CN *DAY_HINH_CN::hinh_cv_max() { int imax = 1; for (int i=2; i h[imax].chu_vi() ) imax = i ; return (h+imax); } void main() { DAY_HINH_CN d; 67
  68. HINH_CN hdtmax; d.nhapsl(); hdtmax = d.hinh_dt_max(); hdtmax.in() ; HINH_CN *hcvmax=d.hinh_cv_max(); hcvmax>in() ; getch(); } Ví d 2 minh ho: + Thuc tính (thành phn d liu) ca lp có th là ñi tưng ca lp khác ñã ñnh nghĩa bên trên. + Phương thc có giá tr tr v kiu ñi tưng + Vai trò ca con tr this (xem phương thc maxdt ca lp TAM_GIAC) + Phương thc tĩnh (xem phương thc tao_tg ca lp TAM_GIAC) Ni dung chương trình là nhp mt dy các ñim, sau ñó tìm tam giác ln nht (v din tích) có ñnh là các ñim va nhp. Chương trình ñưc t chc thành 2 lp: + Lp DIEM gm: Các thuc tính: x và y (to ñ ca ñim) Các phương thc void nhapsl() ; // Nhp x, y void in() ; // In to ñ double do_dai(DIEM d2); // Tính ñ dài ñon thng qua 2 ñim // (ñim n xác ñnh bi this và ñim d2) + Lp TAM_GIAC gm: Các thuc tính: DIEM d1,d2,d3; // 3 ñnh ca tam giác Các phương thc: void nhapsl(); // Nhp to ñ 3 ñnh void in(); // In to ñ 3 ñnh // To mt ñi tưng TAM_GIAC t 3 ñi tưng DIEM static TAM_GIAC tao_tg(DIEM e1, DIEM e2, DIEM e3) double dien_tich() ; // Tính din tích // Tìm tam giác có din tích max trong 2 tam giác *this và t2 TAM_GIAC maxdt(TAM_GIAC t2); 68
  69. + Các vn ñ ñáng chú ý trong chương trình là: Phương thưc tĩnh tao_tg (s gii thích bên dưi) Phương thưc maxdt + Thut toán là: Duyt qua các t hp 3 ñim. Dùng phương thc tao_tg ñ lp tam giác t 3 ñim Dùng phương thc maxdt ñ chn tam giác có din tích ln hơn trong hai tam giác: tam giác va to và tam giác có din tích max (trong s các tam giác ñã to) #include #include #include class DIEM { double x,y; // Toa do cua diem public: void nhapsl() { cout > x >> y ; } void in() { cout << " x = " << x << " y = " << y; } double do_dai(DIEM d2) { return sqrt(pow(xd2.x,2) + pow(yd2.y,2) ); } } ; class TAM_GIAC { DIEM d1,d2,d3; // 3 dinh tam giac public: void nhapsl(); 69
  70. void in(); static TAM_GIAC tao_tg(DIEM e1, DIEM e2, DIEM e3) { TAM_GIAC t; t.d1=e1; t.d2 = e2; t.d3=e3; return t; } double dien_tich() ; TAM_GIAC maxdt(TAM_GIAC t2); } ; void TAM_GIAC::nhapsl() { cout dien_tich() > t2.dien_tich()) return *this ; 70
  71. else return t2; } void main() { DIEM d[50]; int n, i ; clrscr(); cout > n; for (i=1; i<=n; ++i) { cout << "\nNhap diem " << i << " " ; d[i].nhapsl(); } int j, k ; TAM_GIAC tmax, t; tmax = TAM_GIAC::tao_tg(d[1],d[2],d[3]); for (i=1;i<=n2;++i) for (j=i+1;j<=n1;++j) for (k=j+1;k<=n;++k) { t=TAM_GIAC::tao_tg(d[i],d[j],d[k]); tmax = tmax.maxdt(t); } cout << "\n\nTam giac co dien tich lon nhat: " ; tmax.in(); cout << "\nDien tich = " << tmax.dien_tich(); getch(); } Chú ý: ð to mt ñi tưng TAM_GIAC t ba ñi tưng DIEM ta ñã dùng phương thc tĩnh: static TAM_GIAC tao_tg(DIEM e1, DIEM e2, DIEM e3) { TAM_GIAC t; t.d1=e1; t.d2 = e2; t.d3=e3; 71
  72. return t; } Phương thc tĩnh (s nói thêm trong các mc bên dưi) có các ñc ñim sau: + Nó ging phương thc thông thưng ch: Trong thân ca nó có th truy nhp ti các thành phn ca lp (c th là lp TAM_GIAC). + Nó khác phương thc thông thưng ch: Không có ñi ngm ñnh xác ñnh bi con tr this (như phương thc thông thưng). Như vy phương thc tao_tg có ñúng ba ñi. Nó không gn vi mt ñi tưng c th nào ca lp, nên trong li gi ti phương thc o có th dùng tên lp, ví d (xem hàm main): t= TAM_GIAC::tao_tg(d[i], d[j], d[k]); Chú ý: Không th thay phương thc tĩnh tao_tg bng hàm, vì trong thân hàm không ñưc truy xut ñn các thuc tính ca lp TAM_GIAC. Tuy nhiên có mt gii pháp khác là dùng khái nim hàm bn (friend). Hàm bn ca mt lp có quyn truy nhp ñn các thuc tính ca lp. Trong ví d 3 dưi ñây ta s xây dng hàm tao_tg như mt hàm bn ca lp TAM_GIAC. Ngoài ra còn mt gii pháp na là dùng hàm to (constructor) s trình by trong các chương sau. Chương trình dưi ñây có ni dung ging như ví d 2, nhưng thay phương thc tĩnh tao_tg bng hàm bn tao_tg. Ví d 3 (minh ho cách dùng hàm bn) #include #include #include class DIEM { private: double x,y; // Toa do cua diem public: void nhapsl() { cout > x >> y ; } void in() { cout << " x = " << x << " y = " << y; } double do_dai(DIEM d2) { 72
  73. return sqrt(pow(xd2.x,2) + pow(yd2.y,2) ); } } ; class TAM_GIAC { private: DIEM d1,d2,d3; // 3 dinh tam giac public: void nhapsl(); void in(); friend TAM_GIAC tao_tg(DIEM e1, DIEM e2, DIEM e3) { TAM_GIAC t; t.d1=e1; t.d2 = e2; t.d3=e3; return t; } double dien_tich() ; TAM_GIAC maxdt(TAM_GIAC t2); } ; void TAM_GIAC::nhapsl() { cout << "\nDinh 1 " ; d1.nhapsl(); cout << "\nDinh 2 " ; d2.nhapsl(); cout << "\nDinh 3 " ; d3.nhapsl(); } void TAM_GIAC::in() { cout << "\nDinh 1: " ; d1.in(); cout << "\nDinh 2: " ; d2.in(); cout << "\nDinh 3: " ; d3.in(); } double TAM_GIAC::dien_tich() { double a,b,c,p,s; a=d1.do_dai(d2); 73
  74. b=d2.do_dai(d3); c=d3.do_dai(d1); p=(a+b+c)/2; return sqrt(p*(pa)*(pb)*(pc)); } TAM_GIAC TAM_GIAC::maxdt(TAM_GIAC t2) { if (this>dien_tich() > t2.dien_tich()) return *this ; else return t2; } void main() { DIEM d[50]; int n, i ; clrscr(); cout > n; for (i=1; i<=n; ++i) { cout << "\nNhap diem " << i << " " ; d[i].nhapsl(); } int j, k ; TAM_GIAC tmax, t; tmax = tao_tg(d[1],d[2],d[3]); for (i=1;i<=n2;++i) for (j=i+1;j<=n1;++j) for (k=j+1;k<=n;++k) { t=tao_tg(d[i],d[j],d[k]); tmax = tmax.maxdt(t); } cout << "\n\nTam giac co dien tich lon nhat: " ; tmax.in(); cout << "\nDien tich = " << tmax.dien_tich(); 74
  75. getch(); } Chú ý: Hàm bn có th xây dng bên trong ñnh nghĩa lp (như chương trình trên) hoc có th khai báo bên trong và xây dng bên ngoài ñnh nghĩa lp. Không cho phép dùng t khoá friend khi xây dng hàm (bên ngoài lp). class TAM_GIAC { private: DIEM d1,d2,d3; // 3 dinh tam giac public: void nhapsl(); void in(); friend TAM_GIAC tao_tg(DIEM e1,DIEM e2,DIEM e3); double dien_tich() ; TAM_GIAC maxdt(TAM_GIAC t2); } ; TAM_GIAC tao_tg(DIEM e1, DIEM e2, DIEM e3) { TAM_GIAC t; t.d1=e1; t.d2 = e2; t.d3=e3; return t; } § 5. HÀM BN VÀ LP BN 5.1. Hàm bn (friend function) ð mt hàm tr thành bn ca mt lp, có hai cách vit: Cách 1: Dùng t khoá friend ñ khai báo hàm trong lp và xây dng hàm bên ngoài như các hàm thông thưng (không dùng t khoá friend). Mu vit (ví d vi mt lp A có ba hàm bn) như sau: class A { private: // Khai báo các thuc tính public: // Khai báo các hàm bn ca lp A 75
  76. friend void f1( ); friend double f2( ); friend A f3( ) ; } ; // Xây dng các hàm f1, f2, f3 void f1( ) { } double f2( ) { } A f3( ) { } Cách 2: Dùng t khoá friend ñ xây dng hàm trong ñnh nghĩa lp. Mu vit như sau: class A { private: // Khai báo các thuc tính public: // Xây dng các hàm bn ca lp A friend void f1( ) { } friend double f2( ) { } friend A f3( ) { } } ; 5.2. Tính cht ca hàm bn Trong thân hàm bn ca mt lp có th truy nhp ti các thuc tính (k c thuc tính riêng) ca các ñi tưng thuc lp này. ðây là s khác nhau duy nht gia hàm bn và hàm thông thưng. Chú ý rng hàm bn không phi là phương thc ca lp. Phương thc ca lp có mt ñi n (ng vi con tr this) và li gi ca phương thc phi gn vi mt ñi tưng nào ñó (ña ch ñi tưng này ñưc truyn cho con tr this). Li gi ca hàm bn ging như li gi ca hàm thông thưng. Ví d sau s so sánh gia phương thc ca lp và hàm bn. Xét lp SP (s phc). Hãy so sánh hai phương án ñ thc hin vic cng hai s phc: Phương án 1: Dùng phương thc 76
  77. class SP { private: double a; // Phn thc double b; // Phn o public: SP cong(SP u2); } ; SP SP::cong(SP u2) { SP u: u.a = this>a + u2.a ; u.b = this>b + u2.b ; return u; } Cách dùng: SP u, u1, u2; u = u1.cong(u2); Phương án 2: Dùng hàm bn class SP { private: double a; // Phn thc double b; // Phn o public: friend SP cong(SP u1, SP u2); }; SP cong(SP u1, SP u2) { SP u: u.a = u1.a + u2.a ; u.b = u1.b + u2.b ; 77
  78. return u; } Cách dùng: SP u, u1, u2; u = cong(u1, u2); 5.3. Hàm là bn ca nhiu lp Khi mt hàm là bn ca nhiu lp, thì nó có quyn truy nhp ti tt c các thuc tính ca các ñi tưng trong các lp này. ð làm cho hàm f tr thành bn ca các lp A, B và C ta s dng mu vit sau: class A; // Khai báo trưc lp A class B; // Khai báo trưc lp B class C; // Khai báo trưc lp C // ðnh nghĩa lp A class A { // Khai báo f là bn ca A friend void f( ) ; } ; // ðnh nghĩa lp B class B { // Khai báo f là bn ca B friend void f( ) ; } ; // ðnh nghĩa lp C class C { // Khai báo f là bn ca C friend void f( ) ; } ; // Xây dng hàm f void f( ) { } Chương trình sau ñây minh ho cách dùng hàm bn (bn ca mt lp và bn ca nhiu lp). Chương trình ñưa vào hai lp VT (véc tơ), MT (ma trn) và ba hàm bn ñ thc hin các thao tác trên hai lp này: 78
  79. // Hàm bn vi lp VT dùng ñ in mt véc tơ friend void in(const VT &x); // Hàm bn vi lp MT dùng ñ in mt ma trn friend void in(const MT &a); // Hàm bn vi c hai lp MT và VT dùng ñ nhân ma trn vi véc tơ friend VT tich(const MT &a, const VT &x); Ni dung chương trình là nhp mt ma trn vuông cp n và mt véc tơ cp n, sau ñó thc hin phép nhân ma trn vi véc tơ va nhp. #include #include class VT; class MT ; class VT { int n; double x[20]; public: void nhapsl(); friend void in(const VT &x); friend VT tich(const MT &a,const VT &x) ; } ; class MT { int n; double a[20][20]; public: friend VT tich(const MT &a,const VT &x); friend void in(const MT &a); void nhapsl(); } ; void VT::nhapsl() { cout > n ; for (int i=1; i<=n ; ++i) { cout << "\nPhan tu thu " << i << " = " ; 79
  80. cin >> x[i]; } } void MT::nhapsl() { cout > n ; for (int i=1; i > a[i][j]; } } VT tich(const MT &a, const VT &x) { VT y; int n=a.n; if (n!=x.n) return x; y.n = n; for (int i=1; i<=n; ++i) { y.x[i]=0; for (int j=1; j<=n; ++j) y.x[i] += a.a[i][j]*x.x[j]; } return y; } void in(const VT &x) { cout << "\n"; for (int i=1; i<=x.n; ++i) cout << x.x[i] << " "; } 80
  81. void in(const MT &a) { for (int i=1; i<=a.n; ++i) { cout << "\n" ; for (int j=1; j<=a.n; ++j) cout << a.a[i][j] << " "; } } void main() { MT a; VT x,y; a.nhapsl(); x.nhapsl(); y=tich(a,x); cout << "\nMa tran A:"; in(a); cout << "\n\nVec to x: " ; in(x); cout << "\n\nVec to y = Ax: " ; in(y); } 5.4. Lp bn Nu lp A ñưc khai báo là bn ca lp B thì tt c các phương thc ca A ñu là bn ca lp B, tc là có th truy nhp ñn các thành phn riêng ca lp B. Mt lp có th là bn ca nhiu lp khác. Cũng có th khai báo A là bn ca B và B là bn ca A. Gi s có hai lp A và B. ð khai báo lp này là bn ca lp kia, ta vit theo mu sau: // Khai báo trưc các lp class A; class B ; // ðnh nghĩa các lp 81
  82. class A { friend class B ; // Lp B là bn ca A }; class B { friend class A ; // Lp A là bn ca B }; Ví d chương trình dưi ñây có hai lp: MT (ma trn vuông) VT (véc tơ) Lp MT là bn ca VT và lp VT là bn ca MT. Trong chương trình s dng các phương thc trùng tên: Hai phương thc nhp: nhp ma trn nhp véc tơ Hai phương thc in: in ma trn in véc tơ Bn phương thc tính tích: tích ma trn vi ma trn, kt qu là ma trn tích ma trn vi véc tơ, kt qu là véc tơ tích véc tơ vi ma trn, kt qu là véc tơ tích véc tơ vi véc tơ, kt qu là s thc Ni dung chương trình là: + Nhp các ma trn A, B, C + Nhp các véc tơ x, y + Tính tích D = AB + Tính tích u = Dy + Tính tích v = xC + Tính tích s = vu 82
  83. #include #include class MT; class VT ; 83
  84. class MT { double a[10][10]; int n; public: friend class VT; MT() { n=0; } void nhap(); void in(); VT tich(const VT &y); MT tich(const MT &b) ; } ; class VT { double x[10]; int n; public: friend class MT; VT() { n=0; } void nhap(); void in(); VT tich(const MT &b); double tich(const VT &y) ; } ; void MT::nhap() { cout > n; for (int i=1; i<=n; ++i) 84
  85. for (int j=1; j > a[i][j]; } } void MT::in() { for (int i=1; i > n; for (int i=1; i > x[i]; } } void VT::in() { for (int i=1; i<=n; ++i) cout << x[i] << " " ; } VT MT::tich(const VT &y) // tích ma trn nhân véc tơ { VT z; int i,j; 85
  86. for (i=1; i<=n; ++i) { z.x[i] = 0.0 ; for (j=1; j<=n; ++j) z.x[i] += a[i][j]*y.x[j]; } z.n = n; return z; } MT MT::tich(const MT &b) // tích ma trn nhân ma trn { MT c; int i,j,k; for (i=1; i<=n; ++i) for (j=1; j<=n; ++j) { c.a[i][j] = 0.0 ; for (k=1; k<=n; ++k) c.a[i][j] += a[i][k]*b.a[k][j]; } c.n = n; return c; } VT VT::tich(const MT &b) // tích véc tơ nhân ma trn { VT z; int i,j; for (j=1; j<=n; ++j) { z.x[j] = 0.0 ; for (i=1; i<=n; ++i) z.x[j] += b.a[i][j]*x[i]; } z.n = n; return z; } double VT::tich(const VT &y) // tích véc tơ nhân véc tơ 86
  87. { double tg=0.0; for (int i=1; i<=n; ++i) tg += x[i]*y.x[i]; return tg; } void main() { MT a,b,c; VT x,y; clrscr(); cout << "\nMa tran A"; a.nhap(); cout << "\nMa tran B"; b.nhap(); cout << "\nMa tran C"; c.nhap(); cout << "\nvec to X"; x.nhap(); cout << "\nvec to Y"; y.nhap(); MT d= a.tich(b); VT u = d.tich(y); VT v = x.tich(c); double s = v.tich(u); cout << "\n\nVec to v\n"; v.in(); cout << "\n\nMa tran D"; d.in(); cout << "\n\nVec to y\n"; y.in(); cout << "\n\nS= vDy = " << s; getch(); } 87
  88. BÀI TP CHƯƠNG 3 Bài 1. Vit mt lp biu din hình ch nht vi các thuc tính là ñ dài hai cnh và có các phương thc: Nhp d liu hai cnh cho hình ch nht; Tính chu vi hình ch nht; Tính din tích hình ch nht; In thông tin hình ch nht (gm ñ dài hai cnh, chu vi, din tích) ra màn hình. Trên cơ s lp trên vit chương trình cho phép ngưi dùng nhp d liu ca mt hình ch nht, sau ñó in thông tin ca nó ra màn hình. Bài 2. ð qun lý ñim thi vào mt trưng ði hc, ta xây dng lp TS mô t các thí sinh, bao gm: + Các thuc tính: H tên thí sinh; ðim các môn Toán, Lý, Hoá + Các phương thc: Nhp thông tin thí sinh; In thông tin thí sinh; Tính tng ñim ca tng thí sinh Trên cơ s lp trên, vit chương trình làm các công vic sau: + Nhp h tên và ñim ca mt danh sách thí sinh + ðưa ra màn hình danh sách thí sinh trúng tuyn (vi gi thit ñim chun vào trưng là 20) theo th t ñim t cao xung thp. Bài 3. Xây dng lp phân s PS gm: + Các thuc tính: t s và mu s + Các phương thc: Kim tra tính hp l ca phân s; Nhp phân s; In phân s ra màn hình. Bài 4. B sung thêm vào lp PS: các phương thc ñ cng, tr, nhân, chia hai phân s. 89
  89. CHƯƠNG 4 ðNH NGHĨA CHNG TOÁN T ðnh nghĩa chng (overloading) là mt kh năng mnh trong C++ vì nó cho phép xây dng các toán t cn thit trên các lp, giúp cho chương trình ñưc vit ngn gn và rõ ràng hơn. Trong C ++ có th ñnh nghĩa chng hu ht các toán t. Các toán t có th ñưc ñnh nghĩa chng như mt hàm thành phn (phương thc) ca lp hoc như mt hàm bn ca lp. Chương này s trình bày v cách ñnh nghĩa chng và s dng các hàm toán t trong C ++ . § 1. VÍ D TRÊN LP S PHC 1.1. Xây dng hàm bn cng hai s phc Xét mt lp s phc (SP) và xây dng mt hàm bn ñ cng hai s phc như sau: class SP { double a, b; // Phn thc, phn o public: friend SP cong(SP u1, SP u2) { SP u; u.a = u1.a + u2.a ; u.b = u1.b + u2.b ; return u; } }; void main() { SP u, u1, u2; u = cong(u1, u2); // u là tng u1+u2 } 1.2. Xây dng hàm toán t cng hai s phc Trong ví d v lp SP trên, chúng ta ñã xây dng hàm cng hai s phc bng cách s dng hàm bn. Tuy vy, trong trưng hp này, chúng ta có th không cn s dng hàm bn vì ch làm vic vi mt lp. 90
  90. Ví d sau có cùng mc ñích (cng hai s phc) nhưng xây dng hàm cong là mt phương thc ca lp SP: class SP { double a, b; // Phn thc, phn o public: SP cong(SP u2); }; SP SP::cong(SP u2) { SP u; u.a= a+u2.a; u.b= b+u2.b; return u; } void main() { SP u, v, u1, u2, u3, u4; u= u1.cong(u2); // u là tng u1+u2 v= u1.cong(u2.cong(u3.cong(u4))); // v là tng u1+u2+u3+u4 } Nhn xét: Vi c hai cách trên (dùng hàm bn và dùng phương thc ca lp), biu thc s phc tp hơn nu có nhiu phép toán s phc (như tính v trong ví d trên). C++ cho ta mt công c ñ gii quyt vn ñ này: ñó là kh năng ñnh nghĩa chng các toán t. Các toán t sau khi ñưc ñnh nghĩa chng cho lp có th s dng vi các ñi tưng ca lp ñó theo cách tương t như vi các bin thuc kiu d liu chun. Ví d: class SP { double a, b; public: SP operator+(SP u2); 91
  91. }; SP SP::operator+(SP u2) { SP u; u.a= a+u2.a; u.b= b+u2.b; return u; } void main() { SP u, v, u1, u2, u3, u4; u= u1+u2; // u là tng u1+u2 v= u1+u2+u3+u4; // v là tng u1+u2+u3+u4 } Nhn xét: Toán t cng ‘+’ ñóng vai trò như hàm cong ví d trên, và thc cht chương trình dch cũng hiu nó như mt hàm. Nói cách khác ch th u= u1+u2 trong trưng hp này ñưc hiu là u= u1.operator+(u2). Nhưng rõ ràng cách s dng toán t làm cho các biu thc t nhiên và ngn gn hơn nhiu. § 2. GII HN CA ðNH NGHĨA CHNG TOÁN T 2.1. Các toán t có th ñnh nghĩa chng Phn ln các toán t trong C ++ ñu có th ñnh nghĩa chng, ngoi tr các toán t truy nhp vào các thành phn ‘.’, toán t xác ñnh phm vi ‘::’, toán t ñiu kin ‘?:’ và toán t sizeof. Chú ý rng ngay trong cm t “ñnh nghĩa chng” ñã phn ánh rõ: không th to ra các toán t mi mà ch ñnh nghĩa li các toán t ñã có ñ có th làm vic vi nhng kiu d liu khác vi thit k chun ca nó. 2.2. Các nguyên tc khi ñnh nghĩa chng toán t Các toán t ñnh nghĩa chng phi bo toàn s ngôi ca chính toán t ñó (theo cách hiu thông thưng), ví d có th ñnh nghĩa toán t ‘‘ mt ngôi (ño du) và hai ngôi nhưng không th ñnh nghĩa toán t gán ‘=’ là mt ngôi. Các toán t ñnh nghĩa chng nên bo toàn ý nghĩa nguyên thy ca nó, ví d ta có th ñnh nghĩa chng toán t ‘‘ ñ thc hin phép cng (hai ñi tưng), nhưng ñiu ñó rõ ràng không có ích li gì mà d gây ra nhm ln. Các hàm toán t có th ñưc ñnh nghĩa như là hàm thành phn ca lp hoc như mt hàm bn: 92