C++ và Lập trình hướng đối tượng - Chương 3: Khái niệm về lớp
Như đã nói ở trên, lớp là khái niệm trung tâm của lập trình hướng đối tượng, nó là sự mở rộng của các khái niệm cấu trúc (struct) của C và bản ghi (record) của PASCAL. Ngoài các thành phần dữ liệu (như cấu trúc), lớp còn chứa các thành phần hàm , còn gọi là phương thức (method) hay hàm thành viên (member function). Cũng giống như cấu trúc, lớp có thể xem như một kiểu dữ liệu. Vì vậy lớp còn gọi là kiểu đối tượng và lớp được dùng để khai báo các biến, mảng đối tượng (như thể dùng kiểu int để khai báo các biến mảng nguyên). Như vậy từ một lớp có thể tạo ra (bằng cách khai báo) nhiều đối tượng (biến, mảng) khác nhau. Mỗi đối tượng có vùng nhớ riêng của mình. Vì vậy cũng có thể quan niệm lớp là tập hợp các đối tượng cùng kiểu.
Chương này sẽ trình bầy cách định nghĩa lớp, cách xây dựng phương thức, giải thích về phạm vi truy nhập, sư dụng các thành phần của lớp, cách khai báo biến, mảng cấu trúc, lời gọi tới các phương thức.
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àm bạ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àm bạn để thực hiện các thao tác trên 2 lớp này: // Hàm bạn với lớp VT dùng để in một véc tơ friend void in(const VT &x); // Hàm bạn với lớp MT dùng để in một ma trận friend void in(const MT &a); // Hàm bạ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 #include #include 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]; } } void MT::nhapsl() { cout << "\n Cap ma tran = "; cin >> n ; for (int i=1; i<=n ; ++i) for (int j=1; j<=n; ++j) { cout << "\nPhan tu thu hang "<< i << " cot " << j << "=" ; cin >> 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] << " "; } 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; clrscr(); a.nhapsl(); x.nhapsl(); y=tich(a,x); clrscr(); cout << "\nMa tran A:"; in(a); cout << "\n\nVec to x: " ; in(x); cout << "\n\nVec y = Ax: " ; in(y); getch(); } Đ 7. Phạm vi truy xuất 7.1. Các từ khoá private và public Các thành phần (thuộc tính và phương thức) của lớp có thể khai báo là private hoặc public theo mẫu: private: // Khai báo các thành phần riêng của lớp public: // Khai báo các thành phần chung (công cộng) Chú ý: Các thành phần khai báo mặc định (không dùng các từ khoá private và public) được xem là các thành phần private. 7.2. Các thành phần riêng của lớp chỉ được sử dụng trong phạm vi của lớp (trong thân các phương thức của lớp). Chúng không thể đem ra sử dụng bên ngoài lớp. + Một thuộc tính private: Thuộc tính này (của một đối tượng nào đó) chỉ có thể được sử dụng trong thân của các phương thức cùng lớp. + Một phương thức private: Chỉ được sử dụng trong thân của các phương thức cùng lớp. Ví dụ sau minh hoạ cách dùng phương thức private. Xét lớp PS (phân số) với 2 thuộc tính nguyên là t (tử) và m (mẫu). Giả sử cần xây dựng các phương thức để thực hiện các phép toán cộng trừ, nhân, chia phân số. Do các phép toán này cần dùng trong toàn bộ chương trình, nên các phương thức thực hiện các phép toán cần khai báo là public. Để thực hiện các phép tính trên phân số cần dùng đến phép rút gọn phân số. Ta có thể dùng một phương thức private để làm điều này vì việc rút gọn chỉ dùng trong nội bộ lớp. 7.3. Các thành phần công cộng của lớp có phạm vi sử dụng trong toàn chương trình. Như vậy nếu một thuộc tính được khai báo là public, thì nó có thể được truy nhập trong thân của bất kỳ hàm nào trong chương trình. Ví dụ trong Đ6 đã chỉ ra phương án dùng một hàm (tự do) để thực hiện phép cộng 2 số phức như sau là sai: 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; } Tuy nhiên nếu sửa chữa bằng cách khai báo các thuộc tính a và b là public thì lại được. Nhận xét: Các thuộc tính thường khai báo là private để đảm bảo tính dấu kín, an toàn dữ liệu của lớp. Đ 8. Các phương thức toán tử 8.1. Cách đặt tên Các phương thức toán tử được xây dựng như các phương thức thông thường, chỉ có khác cách đặt tên. Tên các phương thức toán tử (cũng giống như hàm toán tử) được tạo bằng cách ghép từ khoá operator với một phép toán, ví dụ: operator+ operator<< operator>> 8.2. Con trỏ this Cũng giống như phương thức thông thường, phương thức toán tử có đối đầu tiên (đối không tường minh) là con trỏ this. 8.3. Toán tử một toán hạng Các phương thức toán tử một toán hạng: Dùng ngay con trỏ this để biểu thị toán hạng duy nhất này, nên trong phương thức sẽ không có đối tường minh. Ví dụ phương thức toán tử - (đổi dấu) một đối tượng kiểu SP (số phức) có thể viết như sau: class SP { private: double a; // Phần thực double b; // Phần ảo public: SP operator-(); } ; SP SP:: operator-() { SP u ; u.a = - this->a ; u.b = - this->b ; return u; } Cách dùng: SP u, v; u = -v; 8.4. Toán tử hai toán hạng Các phương thức toán tử hai toán hạng: Con trỏ this ứng với toán hạng thứ nhất, nên trong phương thức chỉ cần dùng một đối tường minh để biểu thị toán hạng thứ hai. Ví dụ phương thức toán tử + (cộng) hai đối tượng kiểu SP (số phức) có thể viết như sau: class SP { private: double a; // Phần thực double b; // Phần ảo public: SP operator+(SP u2); } ; SP SP:: operator+(SP u2) { SP u ; u.a = this->a + u2.a ; u.b = this->b + u2.b ; return u; } Cách dùng: SP p, p, r; r = p + q ; 8.5. Lớp DT (Đa thức) Chương trình sau sẽ định nghĩa lớp DT và đưa vào các phương thức, hàm: + Các thuộc tính: int n ; // bậc đa thức double *a ; // trỏ tới vùng nhớ chứa các hệ số đa thức + Các phương thức operator+, operator- dùng để đổi dấu các hệ số đa thức operator+ dùng để cộng 2 đa thức operator- dùng để trừ 2 đa thức operator* dùng để nhân 2 đa thức operator^ dùng để tính giá trị đa thức operator[] dùng để cho biết bậc và hệ số của đa thức + Các hàm bạn: operator<< dùng để in các hệ số đa thức operator>> dùng để nhập các hệ số đa thức + Hàm (tự do) double F(DT p, double x) dùng để tính p(x)-giá trị đa thức tại x + Nói thêm về phương thức chỉ số và hàm tự do F - Nếu p là đối tượng của lớp DT, thì hàm chỉ số cho biết: p[-1] = double(n) p[i] = a[i] , i=0, 1, ..., n - Hàm tự do F sẽ dùng phương thức chỉ số để xác định n , các hệ số đa thức và dùng chúng để tính giá trị đa thức. + Trong chương trình sử dụng hàm new để cấp phát vùng nhớ chứa hệ số đa thức. + Nội dung chương trình gồm: - Nhập, in các đa thức p, q, r, s - Tính đa thức: f = -(p + q)*(r - s) - Nhập các số thực x1 và x2 - Tính f(x1) (bằng cách dùng phương thức operator^) - Tính f(x2) (bằng cách dùng hàm F) // Chương trình CT3_10.CPP #include #include #include class DT { private: int n; // Bac da thuc double *a; // Tro toi vung nho chua cac he so da thuc // a0, a1,... public: friend ostream& operator<< (ostream& os,const DT &d); friend istream& operator>> (istream& is,DT &d); DT operator-(); DT operator+(const DT &d2); DT operator-(DT d2); DT operator*(const DT &d2); double operator^(const double &x); // Tinh gia tri da thuc double operator[](int i) { if(i<0) return double(n); else return a[i]; } } ; // Ham tinh gia tri da thuc double F(DT d,double x) { double s=0.0 , t=1.0; int n; n = int(d[-1]); for (int i=0; i<=n; ++i) { s += d[i]*t; t *= x; } return s; } ostream& operator<< (ostream& os,const DT &d) { os << " - Cac he so (tu ao): " ; for (int i=0 ; i<= d.n ; ++i) os << d.a[i] <<" " ; return os; } istream& operator>> (istream& is,DT &d) { cout << " - Bac da thuc: " ; cin >> d.n; d.a = new double[d.n+1]; cout << "Nhap cac he so da thuc:\n" ; for (int i=0 ; i<= d.n ; ++i) { cout << "He so bac " << i << " = " ; is >> d.a[i] ; } return is; } DT DT::operator-() { DT p; p.n = n; p.a = new double[n+1]; for (int i=0 ; i<=n ; ++i) p.a[i] = -a[i]; return p; } DT DT::operator+(const DT &d2) { DT d; int k,i; k = n > d2.n ? n : d2.n ; d.a = new double[k+1]; for (i=0; i<=k ; ++i) if (i<=n && i<=d2.n) d.a[i] = a[i] + d2.a[i]; else if (i<=n) d.a[i] = a[i]; else d.a[i] = d2.a[i]; i=k; while(i>0 && d.a[i]==0.0) --i; d.n = i; return d ; } DT DT::operator-(DT d2) { return (*this + (-d2)); } DT DT::operator*(const DT &d2) { DT d; int k, i, j; k = d.n = n + d2.n ; d.a = new double[k+1]; for (i=0; i<=k; ++i) d.a[i] = 0; for (i=0 ; i<= n ; ++i) for (j=0 ; j<= d2.n ; ++j) d.a[i+j] += a[i]*d2.a[j] ; return d; } double DT::operator^(const double &x) { double s=0.0 , t=1.0; for (int i=0 ; i<= n ; ++i) { s += a[i]*t; t *= x; } return s; } void main() { DT p,q,r,s,f; double x1,x2,g1,g2; clrscr(); cout > p; cout << "\nDa thuc p " << p ; cout > q; cout << "\nDa thuc q " << q ; cout > r; cout << "\nDa thuc r " << r ; cout > s; cout << "\nDa thuc s " << s ; f = -(p+q)*(r-s); cout > x1; cout > x2; g1 = f^x1; g2 = F(f,x2); cout << "\nDa thuc f " << f ; cout << "\n f("<<x1<<") = " << g1; cout << "\n f("<<x2<<") = " << g2; getch(); } 147 148
File đính kèm:
- C++ và Lập trình hướng đối tượng - Chương 3 Khái niệm về lớp.DOC