Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 12 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
12
Dung lượng
19,14 KB
Nội dung
Hàm,hàmbạn 6.1. Hàm có các tính chất sau: + Phạm vi của hàm là toàn bộ chương trình, vì vậy hàm có thể được gọi tới từ bất kỳ chỗ nào. Như vây trong các phương thức có thể sử dụng hàm. + Đối của hàm có thể là các đối tượng, tuy nhiên có một hạn chế là trong thân hàm không cho phép truy nhập tới thuộc tính của các đối này. Ví dụ giả sử đã định nghĩa lớp: 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; } }; Dùng lớp DIEM, ta xây dựng hàm tính độ dài của đoạn thẳng đi qua 2 điểm như sau: double do_dai(DIEM d1, DIEM d2) { return sqrt(pow(d1.x-d2.x,2) + pow(d1.y-d2.y,2)); } Hàm này sẽ bị báo lỗi khi dịch, vì trong thân hàm không cho phép sử dụng các thuộc tính d1.x, d1.y, d2.x, d2.y của các đối tượng d1 và d2 thuộc lớp DIEM. + Phạm vi sử dụng của các phương thức (public) là toàn chương trình, vì vậy trong thân hàm có thể gọi tới các phương thức. Ví dụ giả sử đã định nghĩa lớp: class DIEM { private: double x,y; // Toa do cua diem public: void nhapsl() { 123 124 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) ); } } ; Khi đó bằng cách dùng phương thức do_dai, ta có thể viết hàm tính diện tích tam giác có đỉnh là các đối tượng d1, d2, d3 của lớp DIEM như sau: double dt_tg(DIEM d1, DIEM d2, DIEM d3) { 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)); } Bằng cách dùng hàm dt_tg, có thể tổ chức lại chương trình tìm tam giác có diện tích lớn nhất (ở mục trên) một cách đơn giản hơn( bỏ đi lớp TAM_GIAC) như ví dụ sau. Ví dụ 1: #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 ; } 125 126 void in() { cout << " x = " << x << " y = " << y; } double do_dai(DIEM d2) { return sqrt(pow(x-d2.x,2) + pow(y-d2.y,2) ); } } ; double dt_tg(DIEM d1, DIEM d2, DIEM d3) { 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)); } void main() { DIEM d[50]; int n, i,j,k,imax,jmax,kmax ; clrscr(); cout << "\n So diem= "; cin >> n; for (i=1; i<=n; ++i) { cout << "\nNhap diem " << i << " - " ; d[i].nhapsl(); } imax=1; jmax=2; kmax=3; for (i=1;i<=n-2;++i) for (j=i+1;j<=n-1;++j) for (k=j+1;k<=n;++k) if (dt_tg(d[i],d[j],d[k]) > dt_tg(d[imax],d[jmax],d[kmax])) { imax = i ; jmax = j; kmax = k; } cout << "\n\nTam giac co dien tich lon nhat: " ; cout << "\nDinh 1 - "; d[imax].in(); 127 128 cout << "\nDinh 2 - "; d[jmax].in(); cout << "\nDinh 3 - "; d[kmax].in(); cout << "\nDien tich = " << dt_tg(d[imax],d[jmax],d[kmax]) ; getch(); } Nhận xét: Chương trình trên làm việc trên mảng d kiểu DIEM. Bây giờ nếu ta dùng mảng ngoài thì từ số thứ tự sẽ suy ra phần tử của mảng. Như vây hàm double dt_tg(DIEM d1, DIEM d2, DIEM d3); có 3 đối kiểu DIEM có thể thay bằng hàm có 3 đối nguyên: double dt_tg(int i, int j, int k); để tính diện tích tam giác có đỉnh là d[i], d[j] và d[k] . ý tưởng này được thể hiện trong ví dụ sau. Ví dụ 2: Chương trình dùng mảng đối tượng ngoài. Chú ý: Khai báo mảng đối tượng phải đặt sau định nghĩa kiểu đối tượng (định nghĩa lớp). #include <conio.h> #include <iostream.h> #include <math.h> double dt_tg(int i, int j, int k); // Khai báo hàm dt_tg class DIEM { private: double x,y; // Toa do cua diem public: void nhapsl(); void in(); double do_dai(DIEM d2); } ; // Chú ý: Khai báo mảng kiểu DIEM phải đặt sau định nghĩa // lớp DIEM DIEM d[50]; void DIEM::nhapsl() { cout << " Toa do x, y: " ; cin >> x >> y ; } void DIEM::in() { cout << " x = " << x << " y = " << y; } double DIEM::do_dai(DIEM d2) { return sqrt(pow(x-d2.x,2) + pow(y-d2.y,2) ); } double dt_tg(int i, int j, int k) { double a,b,c,p,s; a=d[i].do_dai(d[j]); b=d[j].do_dai(d[k]); c=d[k].do_dai(d[i]); p=(a+b+c)/2; return sqrt(p*(p-a)*(p-b)*(p-c)); } void main() { int n, i,j,k,imax,jmax,kmax ; clrscr(); cout << "\n So diem= "; cin >> n; for (i=1; i<=n; ++i) { cout << "\nNhap diem " << i << " - " ; d[i].nhapsl(); } imax=1; jmax=2; kmax=3; for (i=1;i<=n-2;++i) for (j=i+1;j<=n-1;++j) for (k=j+1;k<=n;++k) if (dt_tg(i,j,k) > dt_tg(imax,jmax,kmax)) { imax = i ; jmax = j; kmax = k; } cout << "\n\nTam giac co dien tich lon nhat: " ; cout << "\nDinh 1 - "; d[imax].in(); cout << "\nDinh 2 - "; d[jmax].in(); cout << "\nDinh 3 - "; d[kmax].in(); cout << "\nDien tich = " << dt_tg(imax,jmax,kmax); getch(); } 129 130 6.2. Hàmbạn (friend function) 6.2.1. Để một hàm trở thành bạn của một lớp, có 2 cách viết: Cách 1: Dùng từ khoá friend để khai báo hàm trong lớp và xây dựng hàm bên ngoài như các hàm thông thường (không dùng từ khoá friend). Mẫu viết như sau: class A { private: // Khai báo các thuộc tính public: . // Khai báo các hàmbạn của lớp A friend void f1( .); friend double f2( .); friend A f3( .) ; . } ; // Xây dựng các hàm f1, f2, f3 void f1( .) { . } double f2( .) { . } A f3( .) { . } Cách 2: Dùng từ khoá friend để xây dựng hàm trong định nghĩa lớp. Mẫu viết như sau: class A { private: // Khai báo các thuộc tính public: . // Xây dựng các hàmbạn của lớp A 131 132 void f1( .) { . } double f2( .) { . } A f3( .) { . } . } ; 6.2.2. Tính chất của hàmbạn Trong thân hàmbạn của một lớp có thể truy nhập tới các thuộc tính của các đối tượng thuộc lớp này. Đây là sự khác nhau duy nhất giữa hàmbạn và hàm thông thường. Chú ý rằng hàmbạn không phải là phương thức của lớp. Phương thức có một đối ẩn (ứng với con trỏ this) và lời gọi của phương thức phải gắn với một đối tượng nào đó (địa chỉ đối tượng này được truyền cho con trỏ this). Lời gọi của hàmbạn giống như lời gọi của hàm thông thường. Ví dụ sau sẽ so sánh phương thức, hàmbạn và hàm tự do (hàm thông thường). Xét lớp SP (số phức). Hãy so sánh 3 phương án để thực hiện việc cộng 2 số phức: Phương án 1: Dùng phương thức class SP { private: double a; // Phần thực double b; // Phần ảo public: 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àmbạn class SP { private: double a; // Phần thực double b; // Phần ả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; } }; Cách dùng SP u, u1, u2; u = cong(u1, u2); Phương án 3: Dùng hàm tự do class SP { private: double a; // Phần thực double b; // Phần ảo public: . } ; SP cong(SP u1, SP u2) { SP u: u.a = u1.a + u2.a ; u.b = u1.b + u2.b ; return u; } 133 134 Phương án này không được chấp nhận, Trình biên dịch sẽ báo lỗi vì trong thân hàm không được quyền truy xuất đến các thuộc tính riêng (private) a, b của các đối tượng u, u1 và u2 thuộc lớp SP. 6.2.3. Một hàm có thể là bạn của nhiều lớp được không? Câu trả lời là được. Khi một hàm là bạn của nhiều lớp, thì nó có quyền truy nhập tới tất cả các thuộc tính của các đối tượng trong các lớp này. Để làm cho hàm f trở thành bạn của các lớp A, B và C ta sử dụng mẫu viết sau: class B; // Khai báo trước lớp A class B; // Khai báo trước lớp B class C; // Khai báo trước lớp C // Định nghĩa lớp A class A { // Khai báo f là bạn của A friend void f( .) ; } ; // Định nghĩa lớp B class B { // Khai báo f là bạn của B friend void f( .) ; } ; // Định nghĩa lớp C class C { // Khai báo f là bạn của C friend void f( .) ; } ; // Xây dụng hàm f void f( .) { . } Chương trình sau đây minh hoạ cách dùng hàmbạn (bạn của một lớp và bạn của nhiều lớp). Chương trình đưa vào 2 lớp VT (véc tơ), MT (ma trận) và 3 hàmbạn để thực hiện các thao tác trên 2 lớp này: // Hàmbạn với lớp VT dùng để in một véc tơ friend void in(const VT &x); // Hàmbạn với lớp MT dùng để in một ma trận friend void in(const MT &a); 135 136 // Hàmbạn với cả 2 lớp MT và VT dùng để nhân ma trận với véc tơ friend VT tich(const MT &a,const VT &x); Nội dung chương trình là nhập một ma trận vuông cấp n và một véc tơ cấp n, sau đó thực hiện phép nhân ma trận với véc tơ vừa nhập. // Chương trình CT3_09.CPP #include <conio.h> #include <iostream.h> #include <math.h> class VT; class MT ; class VT { private: int n; double x[20]; // Toa do cua diem public: void nhapsl(); friend void in(const VT &x); friend VT tich(const MT &a,const VT &x) ; } ; class MT { private: 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 Cap vec to = "; cin >> n ; for (int i=1; i<=n ; ++i) { cout << "\nPhan tu thu " << i << " = " ; cin >> x[i]; } . Hàm, hàm bạn 6.1. Hàm có các tính chất sau: + Phạm vi của hàm là toàn bộ chương trình, vì vậy hàm có thể được gọi tới từ bất. trỏ this). Lời gọi của hàm bạn giống như lời gọi của hàm thông thường. Ví dụ sau sẽ so sánh phương thức, hàm bạn và hàm tự do (hàm thông thường). Xét lớp