Khởi tạo và hủy
Tại sao phải khởi tạo và hủy?:
Trong bất cứ một ngôn ngữ lập trình nào trước khi thao tác hay xử lý trên bất kỳ một đối tượng nào chúng ta bắt buộc phải tạo (khởi tạo) chúng. Điều này là dĩ nhiên!!.
Sau khi kết thúc chương trình hoặc không dùng đến một đối tượng nào đó của chương trình, chúng ta nên xóa (hủy) đối tượng tránh việc đối tượng chiếm giữ mãi mãi vùng nhớ được cấp cho đối tượng bởi chương trình để những đối tượng khác có thể được khởi tạo (tránh lãng phí bộ nhớ và làm tăng kích thước chương trình khi chạy).
Vậy tạo và xóa rất quan trọng và thường đi đôi với nhau.
KHỞI TẠO VÀ HỦY Tại sao phải khởi tạo và hủy?: Trong bất cứ một ngôn ngữ lập trình nào trước khi thao tác hay xử lý trên bất kỳ một đối tượng nào chúng ta bắt buộc phải tạo (khởi tạo) chúng. Điều này là dĩ nhiên!!. Sau khi kết thúc chương trình hoặc không dùng đến một đối tượng nào đó của chương trình, chúng ta nên xóa (hủy) đối tượng tránh việc đối tượng chiếm giữ mãi mãi vùng nhớ được cấp cho đối tượng bởi chương trình để những đối tượng khác có thể được khởi tạo (tránh lãng phí bộ nhớ và làm tăng kích thước chương trình khi chạy). Vậy tạo và xóa rất quan trọng và thường đi đôi với nhau. KHỞI TẠO: Hàm khởi tạo: -Hàm khởi tạo là gì? : Hàm khởi tạo là một loại hàm đặc biệt: không có giá trị trả về và có tên trùng với tên của lớp. Nó được trình biên dịch gọi một cách tự động cho mỗi đối tượng tại thời điểm đối tượng đó được định nghĩa. Không có giá trị trả về?? Vì sao?? Có tên trùng với tên lớp?? Vì sao?? -Hàm khởi tạo cũng giống như mọi hàm khác là có thể có tham số và có thể được nạp chồng hàm (overloading) để có thể khởi tạo đối tượng bằng nhiều cách. Hàm khởi tạo bắt buộc phải là hàm thành viên của lớp. -Trình biên dịch tự động tìm gọi một hàm khởi tạo thích hợp trong tất cả các hàm khởi tạo được chồng hàm, một lỗi biên dịch khi ta truyền không đúng các đối số cho hàm khi định nghĩa đối tượng. KHỞI TẠO VÀ HỦY Ví dụ: class Diem { private: int x; int y; public: Diem() { x=0; y=0;} Diem(int a, int b) { x=a; y=b;} }; int main() { Diem a; //hàm a.Diem() được tự động gọi Diem b(1, 2); // hàm b.Diem(int, int) được tự động gọi Diem(1); //báo lỗi return 0; } KHỞI TẠO VÀ HỦY 2. Hàm khởi tạo mặc định (Default Constructor): -Hàm khởi tạo mặc định là hàm khởi tạo không có bất kỳ một tham số nào. -Nếu chúng ta không định nghĩa bất kỳ một hàm khởi tạo nào thì khi đó trình biên dịch sẽ tự động tạo một hàm khởi tạo mặc định (hàm này không làm gì cả). Còn nếu chúng ta có ít nhất một hàm khởi tạo thì trình biên dịch sẽ không tạo ra hàm khởi tạo mặc định mà nó phải được định nghĩa rõ ràng bởi lập trình viên. -Nên nhớ hàm khởi tạo mặc định rất quan trọng khi lớp của chúng ta tồn tại ít nhất một hàm khởi tạo. Có thể thấy rõ điều này qua các ví dụ sau: KHỞI TẠO VÀ HỦY KHỞI TẠO VÀ HỦY class A { private: int x; }; //không có hàm khởi tạo nào int main() { A a; //gọi default constructor A b[3]; //3 lần gọi default constructor tạo 3 đối tượng return 0; } class B { private: int x; public: B(int a){ x=a;} }; //không có hàm khởi tạo mặc định int main() { B a; //gọi default constructor B b[3]={B(), B(2)}; return 0; }// Chương trình báo lỗi khi dịch KHỞI TẠO VÀ HỦY 3. Hàm khởi tạo sao chép (Copy Constructor): -Hàm khởi tạo sao chép là hàm khởi tạo có tham số và một trong các tham số là đối tượng của lớp. Tại sao phải cần hàm khởi tạo sao chép?? Hàm khởi tạo sao chép được gọi khi nào?? Vì vậy trong hàm khởi tạo sao chép tham số đối tượng của lớp bắt buộc phải là tham chiếu (hoặc con trỏ). class Diem { private: int x; int y; public: Diem(int a=0, int b=0) { x=a; y=b;} Diem(Diem& d) { x=d.x; y=d.y;} //copy constructor }; int main() { Diem a; //gọi a.Diem() Diem b(a); //Diem b=a; gọi copy constructor return 0; } KHỞI TẠO VÀ HỦY -Ta cần phân biệt rõ hai trường hợp sau đây: Với khai báo Diem b(a) (hoặc Diem b=a): nghĩa là khởi tạo một đối tượng chưa tồn tại từ một đối tượng đã tồn tại và với khai báo này trình biên dịch sẽ tự động gọi hàm khởi tạo sao chép. Với Diem b; b=a; : nghĩa là sử dụng toán tử gán "=" để gán đối tượng này thành đối tượng kia (cả hai đêu đã tồn tại) và điều này sẽ được gọi đến hàm b.operator=(a). -Cả hai đều giống nhau ở chỗ: nếu ta không định nghĩa rõ ràng hai hàm này thì trình biên dịch sẽ tự động tạo hai hàm này cho lớp và nhiệm vụ của nó là "sao chép bề mặt" từ đối tượng nguồn sang đối tượng đích. KHỞI TẠO VÀ HỦY B. HỦY: Hàm hủy (Destructor): -Hàm hủy là một loại hàm đặc biêt: không có tham số, không có giá trị trả về và có tên trùng với tên lớp (phía trước có thêm dấu "~"). Không tham số, không có giá trị trả về và có tên trùng với tên lớp?? Vì sao?? -Điểm khác biệt giữa hàm khởi tạo và hàm hủy: Hàm khởi tạo được trình biên dịch tự động gọi khi đối tượng được định nghĩa, còn hàm hủy thì ngược lại được trình biên dịch tự động gọi khi đối tượng ra khỏi phạm vi của nó. Hàm khởi tạo có thể được nạp chồng còn hàm hủy thì không, tức là mỗi lớp có nhiều nhất một hàm hủy. class ViDu { public: ViDu() { cout>i; switch(i) { case 1: A a; break; case 2: //Lỗi A b; break; } if (i) goto Nhay; //Lỗi A a; Nhay: getch(); return 0; } Nếu lớp A của ta không định nghĩa hàm khởi tạo thì sẽ không xuất hiện thông báo lỗi, nhưng khi đó các biến thành viên của lớp sẽ chứa giá trị rác và dẫn đến kết quả không mong muốn khi chạy chương trình. KHỞI TẠO VÀ HỦY 3. Phạm vi của biến và đối tượng: -Biến và đối tượng chỉ tồn tại từ lúc chúng được định nghĩa cho đến khi ra ngoài khối mà chúng được định nghĩa, khối đó được đánh mở đầu và kết thúc bằng cặp ngoặc nhọn {…}. -Đối với đối tượng có hàm hủy, khi ra khỏi phạm vi định nghĩa thì trình biên dịch tự động gọi hàm hủy của chính đối tượng đó rồi thu hồi vùng nhớ của đối tượng (trừ những đối tượng được cấp phát động). Ví dụ: int main() { Object a; { Object b; } // gọi destructor của b } //gọi destructor của a
File đính kèm:
- Khởi tạo và hủy.ppt