Bài giảng Lập trình Hướng đối tượng - Chương 3: Đối tượng và Lớp - Lê Đức Thịnh
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 - Chương 3: Đối tượng và Lớp - Lê Đức Thịnh", để 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:
- bai_giang_lap_trinh_huong_doi_tuong_chuong_3_doi_tuong_va_lo.ppt
Nội dung text: Bài giảng Lập trình Hướng đối tượng - Chương 3: Đối tượng và Lớp - Lê Đức Thịnh
- LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG LÊ ĐỨC THỊNH
- Chương III: ĐỐI TƯỢNG VÀ LỚP 1. Đối tượng 2. Lớp 3. Phép gán các đối tượng 4. Hàm thiết lập và hàm hủy bỏ 5. Các thành phần tĩnh 6. Đối tượng hằng 7. Hàm bạn và lớp bạn 8. Ví dụ tổng hợp
- 1. Đối tượng ◼ Một lớp (sau khi định nghĩa) có thể xem như một kiểu đối tượng và có thể dùng để khai báo các biến, mảng đối tượng. ◼ Cách khai báo biến, mảng đối tượng: Tên_lớp danh_sách_đối ; Tên_lớp danh_sách_mảng ; ◼ Ví dụ: DIEM d1, d2, d3 ; // Khai báo 3 biến đối tượng d1, d2, d3 DIEM d[20] ; // Khai báo mảng đối tượng d gồm 20 phần tử
- ◼ Mỗi đối tượng sau khi khai báo sẽ được cấp phát một vùng nhớ riêng để chứa các thuộc tính của chúng. ◼ Thuộc tính của đối tượng: cách viết thuộc tính của đối tượng như sau: tên_đối_tượng.Tên_thuộc_tính ◼ Ví dụ: d1.x // Thuộc tính x của đối tượng d1
- ◼ Sử dụng các phương thức: một phương thức được sử dụng thông qua lời gọi. ◼ Ví dụ lời gọi: d1.nhapsl(); ◼ Con trỏ đối tượng dùng để chứa địa chỉ của biến, mảng đối tượng. Nó được khai báo như sau: Tên_lớp *con trỏ ; ◼ Ví dụ dùng lớp 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 mảng đối tượng
- ◼ và có thể thực hiện các câu lệnh: p1 = &d2 ; // p1 chứa địa chỉ của d2 , hay p1 trỏ tới d2 p2 = d ; // p2 trỏ tới đầu mảng d p3 = new DIEM; // Tạo một đối tượng và chứa địa chỉ của nó vào p3 ◼ Để sử dụng thuộc tính của đối tượng thông qua con trỏ, ta viết như sau: Tên_con_trỏ->Tên_thuộc_tính
- ◼ Con trỏ this là đối thứ nhất của phương thức: C++ sử dụng con trỏ đặc biệt this trong các phương thức. Các thuộc tính viết trong phương thức được hiểu là thuộc một đối tượng do con trỏ this trỏ tới. Như vậy phương thức nhapsl() có thể viết một cách tường minh như sau: void DIEM::nhapsl() { cout > this->x >> this->y ; 103 104 cout > this->m ; }
- 2. Lớp ◼ Lớp được định nghĩa theo mẫu: class tên_lớp { private: // Khai báo các thành phần riêng public: // Khai báo các thành phần công cộng } ; // Định nghĩa (xây dựng) các phương thức ◼ Chú ý: ◼ Thuộc tính của lớp không thể có kiểu của chính lớp đó, nhưng có thể là kiểu con trỏ lớp này, ví dụ:
- class A { A x ; // Không cho phép, vì x có kiểu lớp A A *p ; // Cho phép , vì p là con trỏ kiểu lớp A } ; ◼ Các thành phần private (riêng) chỉ được sử dụng bên trong lớp. ◼ Các thành phần public (công cộng) được phép sử dụng ở cả bên trong và bên ngoài lớp. ◼ Nếu không quy định cụ thể (không dùng các từ khoá private và public) thì C++ hiểu đó là private.
- ◼ Trong thân phương thức của một lớp (giả sử lớp A) có thể sử dụng: + Các thuộc tính của lớp A + Các phương thức của lớp A + Các hàm tự lập trong chương trình. Vì phạm vi sử dụng của hàm là toàn chương trình.
- ◼ Ví dụ: class DIEM { private: int x, y, m ; public: void nhapsl() ; void hien() ; void an() { putpixel(x, y, getbkcolor()); } } ;
- void DIEM::nhapsl() { cout > x >> y ; cout > m ; } void DIEM::hien() { int mau_ht ; mau_ht = getcolor(); putpixel(x, y, m); setcolor(mau_ht); }
- 3. Phép gán các đối tượng ◼ Có thể thực hiện phép gán giữa hai ĐT cùng kiểu. point a, b; a.init(5, 2); b=a; ◼ Về thực chất đó là việc sao chép giá trị các thành phần dữ liệu (x, y) từ ĐT a sang ĐT b. ◼ Khi các ĐT chứa các thành phần dữ liệu động, vùng dữ liệu động không được nhân bản.
- a b x=5 x=5 y=2 y=2 z z vùng dữ liệu động
- 4. Hàm thiết lập và hàm hủy bỏ ◼ Hàm tạo cũng là một phương thức của lớp (nhưng khá đặc biệt) dùng để tạo dựng một đối tượng mới. Chương trình dịch sẽ cấp phát bộ nhớ cho đối tượng sau đó sẽ gọi đến hàm tạo. ◼ Cách viết hàm tạo: + Tên của hàm tạo: Tên của hàm tạo bắt buộc phải trùng với tên của lớp. + Hàm tạo không có kiểu trả về. + Trong một lớp có thể có nhiều hàm tạo (cùng tên nhưng khác bộ đối).
- class DIEM_DH { private: int x, y, m ; public: //Hàm tạo không đối: khởi gán cho x=0, y=0, m=1 // Hàm này viết bên trong định nghĩa lớp DIEM_DH() { x=y=0; m=1; } // Hàm tạo này xây dựng bên ngoài định nghĩa lớp DIEM_DH(int x1, int y1, int m1=15) ; // Các phương thức khác } ;
- // Xây dựng hàm tạo bên ngoài định nghĩa lớp DIEM_DH:: DIEM_DH(int x1, int y1, int m1) { x=x1; y=y1; m=m1; } ◼ Dùng hàm tạo trong khai báo: ◼ Ví dụ: DIEM_DH d; // Gọi tới hàm tạo không đối. Kết quả d.x=0, d.y=0, d.m=1 DIEM_DH u(200,100,4); // Gọi tới hàm tạo có đối. Kết quả u.x=200, u.y=100, d.m=4 DIEM_DH v(300,250); // Gọi tới hàm tạo có đối. Kết quả v.x=300, v.y=250, d.m=15 DIEM_DH p[10] ; // Gọi tới hàm tạo không đối 10 lần
- ◼ Dùng hàm tạo trong cấp phát bộ nhớ: + Khi cấp phát bộ nhớ cho một đối tượng có thể dùng các tham số để khởi gán cho các thuộc tính của đối tượng, ví dụ: DIEM_DH *q =new DIEM_DH(50,40,6);//Gọi tới hàm tạo có đối. Kết quả q->x=50, q->y=40, q->m=6 DIEM_DH *r = new DIEM_DH ; // Gọi tới hàm tạo không đối. Kết quả r->x=0, r->y= 0, r->m=1 + Khi cấp phát bộ nhớ cho một dẫy đối tượng không cho phép dùng tham số để khởi gán, ví dụ: int n=20; DIEM_DH *s = new DIEM_DH[n] ; // Gọi tới hàm tạo không đối 20 lần.
- ◼ Nếu lớp không có hàm tạo, Chương trình dịch sẽ cung cấp một hàm tạo mặc định không đối (default). Hàm này thực chất không làm gì cả. ◼ Nếu trong lớp đã có ít nhất một hàm tạo, thì hàm tạo mặc định sẽ không được phát sinh nữa. ◼ Hàm tạo sao chép mặc định: Ta có thể dùng lệnh khai báo để tạo một đối tượng mới từ một đối tượng đã tồn tại, ví dụ: PS u; PS v(u) ; // Tạo v theo u ◼ Nếu trong lớp PS chưa xây dựng hàm tạo sao chép, thì câu lệnh này sẽ gọi tới một hàm tạo sao chép mặc định (của C++). Hàm này sẽ sao chép nội dung từng bit của u vào các bit tương ứng của v.
- ◼ Cách xây dựng hàm tạo sao chép + Hàm tạo sao chép sử dụng một đối kiểu tham chiếu đối tượng để khởi gán cho đối tượng mới. Hàm tạo sao chép được viết theo mẫu: Tên_lớp (const Tên_lớp & dt) { // Các câu lệnh dùng các thuộc tính của đối tượng dt // để khởi gán cho các thuộc tính của đối tượng mới } ◼ Khi nào cần xây dựng hàm tạo sao chép + Khi lớp không có các thuộc tính kiểu con trỏ hoặc tham chiếu, thì dùng hàm tạo sao chép mặc định là đủ.
- + Khi lớp có các thuộc tính con trỏ hoặc tham chiếu, thì hàm tạo sao chép mặc định chưa đáp ứng được yêu cầu. Ví dụ lớp DT (đa thức): class DT { private: int n; // Bac da thuc double *a; // Tro toi vung nho chua cac he so da thuc // a0, a1, public: DT() { this->n=0; this->a=NULL; }
- DT(int n1) { this->n=n1 ; this->a = new double[n1+1]; } friend ostream& operator > (istream& is,DT &d); } ; void main() { DT d (3); DT u(d) ; // Như vậy 2 con trỏ u.a và d.a cùng trỏ đến một vùng nhớ. }
- ◼ Khi sửa đổi các hệ số của đa thức trong d thì các hệ số của đa thức trong u cũng thay đổi theo. ◼ Hàm tạo sao chép cần được xây dựng như sau: DT::DT(const DT &d) { this->n = d.n; this->a = new double[d.n+1]; for (int i=0;i a[i] = d.a[i]; }
- ◼ Hàm huỷ là một hàm thành viên của lớp (phương thức) có chức năng ngược với hàm tạo. Hàm huỷ được gọi trước khi giải phóng (xoá bỏ) một đối tượng để thực hiện một số công việc có tính “dọn dẹp” trước khi đối tượng được huỷ bỏ. ◼ Hàm huỷ mặc định: Nếu trong lớp không định nghĩa hàm huỷ, thì một hàm huỷ mặc định không làm gì cả được phát sinh.
- ◼ Quy tắc viết hàm huỷ: Mỗi lớp chỉ có một hàm huỷ viết theo các quy tắc sau: + Kiểu của hàm: Hàm huỷ cũng giống như hàm tạo là hàm không có kiểu trả về. + Tên hàm: Tên của hàm huỷ gồm một dẫu ngã (đứng trước) và tên lớp: ~Tên_lớp + Đối: Hàm huỷ không có đối + Ví dụ:
- class DT { private: int n; // Bac da thuc double *a; // Tro toi vung nho chua cac he so da thuc // a0, a1, public: ~DT() { delete this->a; } } ;
- 5. Các thành phần tĩnh ◼ Thành phần dữ liệu tĩnh + Thành phần dữ liệu được khai báo bằng từ khoá static gọi là tĩnh, ví dụ: class A { private: static int ts ; // Thành phần tĩnh int x; } ; + Thành phần tĩnh được cấp phát một vùng nhớ cố định. Nó tồn tại ngay cả khi lớp chưa có một đối tượng nào cả. + Thành phần tĩnh là chung cho cả lớp, nó không phải là riêng của mỗi đối tượng.
- A u,v ; // Khai báo 2 đối tượng thì giữa các thành phần x và ts có sự khác nhau như sau: u.x và v.x có 2 vùng nhớ khác nhau u.ts và v.ts chỉ là một, chúng cùng biểu thị một vùng nhớ + Để biểu thị thành phần tĩnh, ta có thể dùng tên lớp, ví du: Đối với ts thì 3 cách viết sau là tương đương: A::ts u.ts v.ts + Khai báo và khởi gán giá trị cho thành phần tĩnh
- + Thành phần tĩnh sẽ được cấp phát bộ nhớ và khởi gán giá trị ban đầu bằng một câu lệnh khai báo đặt sau định nghĩa lớp (bên ngoài các hàm, kể cả hàm main), theo các mẫu: int A::ts ; // Khởi gán cho ts giá trị 0 int A::ts = 1234; // Khởi gán cho ts giá trị 1234 Chú ý: Khi chưa khai báo thì thành phần tĩnh chưa tồn tại. + Các thuộc tính tshd và tstienban là chung cho cả lớp nên chúng được chọn là các thuộc tính tĩnh.
- ◼ Phương thức tĩnh: + Có 2 cách viết phương thức tĩnh: Cách 1: Dùng từ khoá static đặt trước định nghĩa phương thức viết bên trong định nghĩa lớp. Cách 2: Nếu phương thức xây dựng bên ngoài định nghĩa lớp, thì dùng từ khoá static đặt trước khai báo phương thức bên trong định nghĩa lớp. Chú ý không cho phép dùng từ khoá static đặt trước định nghĩa phương thức viết bên ngoài định nghĩa lớp.
- class HDBH { private: int shd ; char *tenhang ; double tienban ; static int tshd ; static double tstienban ; public: static void in() { cout <<"\n" << tshd; cout <<"\n" << tstienban; cout <<"\n" << tenhang; cout <<"\n" << tienban; } } ;
- 6. Đối tượng hằng 6.1 Đối tượng hằng class point { int x, y; public: point( ); void display() const; //PT hằng void move( ); }; ◼ chỉ có thể sử dụng phương thức thiết lập hoặc hủy bỏ hoặc PT hằng. 6.2 Hàm thành phần hằng ◼ sau danh sách tham số có từ khóa const. ◼ Không thể thay đổi nội dung của ĐT. ◼ const cần được mô tả trong cả khai báo và định nghĩa.
- 7. Hàm bạn và lớp bạn ◼ Hàm bạn của một lớp, tuy không phải là phương thức của lớp, nhưng có thể truy nhập đến các thành phần riêng (private) của lớp. Một hàm có thể là bạn của nhiều lớp. ◼ Nếu lớp A được khai báo là bạn của lớp B thì tất cả các phương thức của A đều có thể truy nhập đến các thành phần riêng của lớp B. Một lớp có thể là bạn của nhiều lớp khác. Cũng có thể khai báo A là bạn của B và B là bạn của A.
- ◼ Cách khai báo lớp bạn: Giả sử có 3 lớp A, B và C. Để khai báo lớp này là bạn của lớp kia, ta viết theo mẫu sau: // Khai báo trước các lớp class A; class B ; class C; // Định nghĩa các lớp class A { friend class B ; // Lớp B là bạn của A friend class C ; // Lớp C là bạn của A };
- class B { friend class A ; // Lớp A là bạn của B friend class C ; // Lớp C là bạn của B }; class C { friend class A ; // Lớp A là bạn của C friend class B ; // Lớp B là bạn của C };
- 8. Ví dụ tổng hợp class vector { static int n; //số chiều của vector float *v; //vùng nhớ chứa tọa độ public: vector(); vector(float *); vector(vector &); //hàm thiết lập sao chép ~vector(); static int & Size() { return n;} friend vector prod(matrix &, vector &); friend class matrix; }; int vector::n = 0;
- class matrix { static int n; //số chiều của vector vector *m; //vùng nhớ chứa các tọa độ public: matrix(); ~matrix(); void display(); static int & Size() { return n;} friend vector prod(matrix &, vector &); }; int matrix::n = 0;
- 9. Bài tập ◼ Bài tập chương 2 sách Nguyễn Thanh Thủy, Bài tập lập trình hướng đối tượng với C++, NXB Khoa học kỹ thuật Hà Nội 2001.