Nóithêmvềkiểuphươngthứcvàkiểuđốicủaphươngthức 5.1. KiểuphươngthứcPhươngthức có thể không có giá trị trả về (kiểu void) hoặc có thể trả về một giá trị có kiểu bất kỳ, kể cả giá trị kiểuđối tượng, con trỏ đối tượng, tham chiếu đối tượng. 5.2. ĐốicủaphươngthứcĐốicủaphươngthức (cũng giống như đốicủa hàm) có thể có kiểu bất kỳ: + Kiểu dữ liệu chuẩn như int, float, char, . . Con trỏ hoặc tham chiếu đến kiểu dữ liệu chuẩn như int*, float*, char*, int&, float&, char&, . + Các kiểu ngoài chuẩn đã định nghĩa trước như đối tượng, cấu trúc, hợp, enum, . . Con trỏ hoặc tham chiếu đến các kiểu ngoài chuẩn này. + Kiểuđối tượng của chính phương thức, con trỏ hoặc tham chiếu đến kiểuđối tượng này. 5.3. Các ví dụ Ví dụ 1 minh hoạ: + Thuộc tính (thành phần dữ liệu) của lớp có thể là đối tượng của lớp khác đã định nghĩa bên trên. + Phươngthức có giá trị trả vềkiểuđối tượng và con trỏ đối tượng. Nội dung chương trình là nhập một dẫy hình chữ nhật, sau đó tìm hình chữ nhật có max diện tích và hình chữ nhật có max chu vi. Chương trình được tổ chức thành 2 lớp: + Lớp HINH_CN gồm: - Các thuộc tính: d và r (chiều dài và chiều rộng) - Các phươngthức void nhapsl() ; // Nhập chiều dài, rộng int dien_tich(); // Tính diện tích int chu_vi() ; // Tính chu vi + Lớp DAY_HINH_CN gồm - Các thuộc tính: int n ; //số hình chữ nhật của dẫy HINH_CN *h; //Con trỏ tới dẫy đối tượng của lớp HINH_CN - Các phươngthức void nhapsl(); // Nhập một dẫy hình chữ nhật HINH_CN hinh_dt_max() ; //Trả về hình chữ nhật có // diện tích max HINH_CN *hinh_cv_max() ; // Trả về con trỏ tới HCN có // chu vi max #include <conio.h> #include <iostream.h> class HINH_CN { private: int d, r; // chieu dai va chieu rong public: void nhapsl() { cout << " \nNhap chieu dai va chieu rong: " ; cin >> 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 { private: 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 << "So hinh CN = " ; cin >> n; h = new HINH_CN[n+1]; for (int i=1;i<=n;++i) h[i].nhapsl(); 111 112 } HINH_CN DAY_HINH_CN::hinh_dt_max() { HINH_CN hdtmax; hdtmax = h[1]; for (int i=2; i<=n; ++i) if (h[i].dien_tich() > hdtmax.dien_tich() ) hdtmax = h[i]; return hdtmax; } HINH_CN *DAY_HINH_CN::hinh_cv_max() { int imax = 1; for (int i=2; i<=n; ++i) if (h[i].chu_vi() > h[imax].chu_vi() ) imax = i ; return (h+imax); } void main() { DAY_HINH_CN d; 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ạ: + Thuộc tính (thành phần dữ liệu) của lớp có thể là đối tượng của lớp khác đã định nghĩa bên trên. + Phươngthức có giá trị trả vềkiểuđối tượng + Vai trò của con trỏ this (xem phươngthức maxdt của lớp TAM_GIAC) + Phươngthức tĩnh (xem phươngthức tao_tg của lớp TAM_GIAC) Nội dung chương trình là nhập một dẫy các điểm, sau đó tìm tam giác lớn nhất (về diện tích) có đỉnh là các điểm vừa nhập. Chương trình được tổ chức thành 2 lớp: 113 114 + Lớp DIEM gồm: - Các thuộc tính: x và y (toạ độ của điểm) - Các phươngthức void nhapsl() ; // Nhập x, y void in() ; // In toạ độ double do_dai(DIEM d2) ; // Tính độ dài đoạn thẳng qua // 2 điểm (điểm ẩn xác định bởi this và điểm d2) + Lớp TAM_GIAC gồm: - Các thuộc tính: DIEM d1,d2,d3; // 3 đỉnh của tam giác - Các phương thức: void nhapsl(); // Nhập toạ độ 3 đỉnh void in(); // In toạ độ 3 đỉnh // Tạo một đố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 diện tích // Tìm tam giác có diện tích max trong 2 tam giác *this và t2 TAM_GIAC maxdt(TAM_GIAC t2); + Các vấn đề đáng chú ý trong chương trình là: - Phươngthưc tĩnh tao_tg (sẽ giải thích bên dưới) - Phươngthưc maxdt + Thuật toán là: - Duyệt qua các tổ hợp 3 điểm. - Dùng phươngthức tao_tg để lập tam giác từ 3 điểm - Dùng phươngthức maxdt để chọn tam giác có diện tích lớn hơn trong 2 tam giác: tam giác vừa tạo và tam giác có diện tích max (trong số các tam giác đã tạo) #include <conio.h> #include <iostream.h> #include <math.h> class DIEM { private: double x,y; // Toa do cua diem public: void nhapsl() { cout << " Toa do x, y: " ; cin >> x >> y ; } void in() { cout << " x = " << x << " y = " << y; } double do_dai(DIEM d2) { return sqrt(pow(x-d2.x,2) + pow(y-d2.y,2) ); } } ; class TAM_GIAC { private: DIEM d1,d2,d3; // 3 dinh tam giac public: void nhapsl(); 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 << "\nDinh 1 - " ; d1.nhapsl(); cout << "\nDinh 2 - " ; d2.nhapsl(); cout << "\nDinh 3 - " ; d3.nhapsl(); } void TAM_GIAC::in() { cout << "\nDinh 1: " ; d1.in(); 115 116 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); b=d2.do_dai(d3); c=d3.do_dai(d1); p=(a+b+c)/2; return sqrt(p*(p-a)*(p-b)*(p-c)); } 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 So diem= "; cin >> 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<=n-2;++i) for (j=i+1;j<=n-1;++j) for (k=j+1;k<=n;++k) { t=TAM_GIAC::tao_tg(d[i],d[j],d[k]); tmax = tmax.maxdt(t); 117 118 } cout << "\n\nTam giac co dien tich lon nhat: " ; tmax.in(); cout << "\nDien tich = " << tmax.dien_tich(); getch(); } Chú ý 1: Để tạo một đối tượng TAM_GIAC từ 3 đối tượng DIEM ta đã dùng phươngthức 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; return t; } Phươngthức tĩnh (sẽ nóithêm trong các mục bên dưới) có các đặc điểm sau: + Nó giống phươngthức thông thường ở chỗ: Trong thân của nó có thể truy nhập tới các thành phần của lớp (cụ thể là lớp TAM_GIAC). + Nó khác phươngthức thông thường ở chỗ: - Không có đối ngầm định xác định bởi con trỏ this (như phươngthức thông thường). Như vậy phươngthức tao_tg có đúng 3 đối. - Nó không gắn với một đối tượng cụ thể nào của lớp, nên trong lời gọi tới phươngthức ảo có thể dùng tên lớp, ví dụ (xem hàm main): t=TAM_GIAC::tao_tg(d[i],d[j],d[k]); Chú ý 2: Không thể thay phươngthức tĩnh tao_tg bằng hàm, vì trong thân hàm không được truy xuất đến các thuộc tính của lớp TAM_GIAC. Tuy nhiên có một giải pháp khác là dùng khái niệm hàm bạn (friend). Hàm bạn của một lớp có quyền truy nhập đến các thuộc tính của lớp. Trong ví dụ 3 dưới đây ta sẽ xây dựng hàm tao_tg như một hàm bạn của lớp TAM_GIAC. Chú ý 3: còn một giải pháp nữa là dùng hàm tạo (constructor) sẽ trình bầy trong các chương sau: Chương trình dưới đây có nội dung giống như ví dụ 2, nhưng thay phươngthức tĩnh tao_tg bằng hàm bạn tao_tg. Ví dụ 3: Minh hoạ cách dùng hàm bạn. Nội dung chương trình giống như trong ví dụ 2. #include <conio.h> #include <iostream.h> #include <math.h> class DIEM { private: double x,y; // Toa do cua diem public: void nhapsl() { cout << " Toa do x, y: " ; cin >> x >> y ; } void in() { cout << " x = " << x << " y = " << y; } double do_dai(DIEM d2) { return sqrt(pow(x-d2.x,2) + pow(y-d2.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() 119 120 { 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); b=d2.do_dai(d3); c=d3.do_dai(d1); p=(a+b+c)/2; return sqrt(p*(p-a)*(p-b)*(p-c)); } 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 So diem= "; cin >> 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<=n-2;++i) for (j=i+1;j<=n-1;++j) 121 122 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(); getch(); } Chú ý: Hàm bạn có thể xây dựng bên trong định nghĩa lớp (như chương trình trên) hoặc có thể khai báo bên trong và xây dựng bên ngoài định nghĩa lớp như sau: 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; } Nhận xét: Không cho phép dùng từ khoá friend khi xây dựng hàm (bên ngoài lớp) . Nói thêm về kiểu phương thức và kiểu đối của phương thức 5.1. Kiểu phương thức Phương thức có thể không có giá trị trả về (kiểu void) hoặc có thể trả về. có kiểu bất kỳ, kể cả giá trị kiểu đối tượng, con trỏ đối tượng, tham chiếu đối tượng. 5.2. Đối của phương thức Đối của phương thức (cũng giống như đối của