Lập trình hướng đối tượng - Chương 6: Khởi tạo và hủy

Trong C + +, khái niệm về khởi tạo (initialization) và hủy (cleanup) là điều cần thiết cho việc sử dụng thư viện dễ dàng và để loại bỏ các lỗi khó thấy xảy ra khi các lập trình viên quên thực hiện hoạt động này.

Chương này kiểm tra các tính năng trong C+ + giúp khởi tạo và hủy đúng cách.

 

ppt40 trang | Chuyên mục: Lập Trình Hướng Đối Tượng | Chia sẻ: dkS00TYs | Lượt xem: 1895 | Lượt tải: 0download
Tóm tắt nội dung Lập trình hướng đối tượng - Chương 6: Khởi tạo và hủy, để xem tài liệu hoàn chỉnh bạn click vào nút "TẢI VỀ" ở trên
or and Destructor) Thinking in C++, by Bruce Eckel University of information technology Object Oriented Programming Trong C + +, khái niệm về khởi tạo (initialization) và hủy (cleanup) là điều cần thiết cho việc sử dụng thư viện dễ dàng và để loại bỏ các lỗi khó thấy xảy ra khi các lập trình viên quên thực hiện hoạt động này. Chương này kiểm tra các tính năng trong C+ + giúp khởi tạo và hủy đúng cách. Giới thiệu sơ lược về nội dung ĐẢM BẢO KHỞI TẠO VỚI CONSTRUCTOR Guaranteed initialization with the constructor - Trong C + +, khởi tạo là một bước quan trọng mà các lập trình viên cần thực hiện. Nếu một lớp có một hàm khởi tạo, trình biên dịch tự động gọi hàm khởi tạo tại điểm đối tượng được tạo ra. Vấn đề tên của hàm khởi tạo: có 2 vấn đề đặt ra + Đầu tiên là bất kỳ tên nào mà bạn sử dụng có tiềm năng có thể xung đột với một tên mà bạn sử dụng như là một thành viên trong lớp. + Trình biên dịch có trách nhiệm kêu gọi các hàm khởi tạo nó luôn luôn phải biết được chức năng để gọi. ĐẢM BẢO KHỞI TẠO VỚI CONDTRUCTOR Guaranteed initialization with the constructor Ví dụ đơn giản với constructor: class X { 	 int i; 	public: 	 X(); // Constructor }; //Now, when an object is defined, void f() { 	X a; 	// ... 	} khi chương trình chạy tới điểm thực hiện, nơi được xác định, hàm khởi tạo được gọi tự động. Lúc đó, trình biên dịch lặng lẽ chèn lệnh gọi X:: X () cho đối tượng một tại điểm của định nghĩa. ĐẢM BẢO KHỞI TẠO VỚI CONSTRUCTOR 	Guaranteed initialization with the constructor Chức năng của hàm khởi tạo: Khởi tạo bộ nhớ đúng cách. Constructor đối số cung cấp cho bạn một cách để bảo đảm rằng tất cả các phần của đối tượng của bạn được khởi tạo các giá trị thích hợp. Tránh việc trả về các giá trị không mong muốn. 	ví dụ: Tree t(12); // 12-foot tree ĐẢM BẢO KHỞI TẠO VỚI CONSTRUCTOR	 Guaranteed initialization with the constructor Tóm lược về hàm khởi tạo: Hàm khởi tạo là một hàm thành viên đặc biệt dùng để khởi tạo một đối tượng. Nó có tên trùng với lớp chứa nó. Không có kiểu trả về Khai báo trong hoặc ngoài lớp như đối với các hàm thành viên. Có thể định nghĩa nhiều hàm khởi tạo theo các cách khởi tạo khác nhau. ĐẢM BẢO KHỞI TẠO VỚI CONSTRUCTOR	 Guaranteed initialization with the constructor Các hàm khởi tạo phải có đối số khác nhau sao cho trình biên dịch có thể phân biệt và lựa chọn đúng hàm cho mỗi cách dùng. Hàm khởi tạo mặc định ( Default function) không có đối số. ĐẢM BẢO HỦY VỚI DESTRUCTORGuaranteed cleanup with the Destructor * Cách khai báo destructor: - Destructor là một thủ tục cũng không kém phần quan trọng như Constructor. - Được khai báo trùng với tên lớp giống nhưng constructor nhưng có thêm dấu ngã (~ ) ở đằng trước: 	ví dụ: 	 class Y { 	public: 	~Y(); }; ĐẢM BẢO HỦY VỚI DESTRUCTORGuaranteed cleanup with the Destructor Đặc tính của destructor: Destructor đặc biệt phù hợp khi mà một đối tượng cấp phát bộ nhớ động trong quá trình tồn tại của nó và trong thời điểm bị hủy bỏ chúng ta muốn giải phóng bộ nhớ mà nó sử dụng. Là một hàm thành viên được gọi tự động khi đối tượng hủy. Ta không thể gọi trực tiếp hàm này, mà bộ biên dịch sẽ phát lời gọi đến hàm khi một đối tượng vượt ra ngoài phạm vi. Không có đối số và kiểu trả về. Thường giải phóng bộ nhớ cho toán tử new bằng delete. ĐẢM BẢO HỦY VỚI DESTRUCTORGuaranteed cleanup with the Destructor //: C06:Constructor1.cpp #include using namespace std; class Tree { int height; public: Tree(int initialHeight); // Constructor ~Tree(); // Destructor void grow(int years); void printsize(); }; Tree::Tree(int initialHeight) { height = initialHeight; } Tree::~Tree() { cout #include using namespace std; class G { int i; public: G(int ii); }; G::G(int ii) { i = ii; } int main() { cout > retval; require(retval != 0); int y = retval + 3; G g(y); } ///:~ Ví dụ về khởi tạo và định nghĩa cùng lúc XÓA BỎ KHỐI ĐỊNH NGHĨAElimination of the definition block Qua ví dụ có thể thấy rằng một số mã được thực thi, sau đó retval được định nghĩa, khởi tạo, và được sử dụng để nắm bắt đầu vào người sử dụng, và sau đó y và g được xác định. C, mặt khác, không cho phép một biến được xác định bất cứ nơi nào, ngoại trừ vào đầu phạm vi. XÓA BỎ KHỐI ĐỊNH NGHĨAElimination of the definition block Ta cần định nghĩa biến càng gần điểm của hàm sử dụng nhất có thể, và luôn luôn khởi tạo cho họ khi hàm được định nghĩa. (Đây là một gợi ý cho phong cách xây dựng trong các loại, nơi khởi là tùy chọn) 	Đây là một vấn đề an toàn.. Bằng cách giảm thời gian sẵn có của biến trong phạm vi này, bạn đang làm giảm cơ hội nó sẽ được sử dụng sai trong một số phần khác trong phạm vi. Ngoài ra, dễ đọc được cải thiện, vì người đọc không phải nhảy lui về đầu của phạm vi biết kiểu của một biến. VÒNG LẶPfor loops * Trong C + +, bạn thường sẽ cho thấy một vòng lặp truy cập được xác định ngay trong những biểu hiện như: 	 	for (int j = 0; j #include using namespace std; const int increment = 100; Stash::Stash(int sz) { size = sz; quantity = 0; storage = 0; next = 0; } int Stash::add(void* element) { if(next >= quantity) 	inflate(increment); int startBytes = next * size; unsigned char* e = (unsigned char*)element; for(int i = 0; i = next) return 0; return &(storage[index * size]); } int Stash::count() { return next; void Stash::inflate(int increase) { require(increase > 0, "Stash::inflate zero or negative increase"); int newQuantity = quantity + increase; int newBytes = newQuantity * size; int oldBytes = quantity * size; unsigned char* b = new unsigned char[newBytes]; for(int i = 0; i #include #include int main() { Stash intStash(sizeof(int)); for(int i = 0; i data; } void* Stack::pop() { if(head == 0) return 0; void* result = head->data; Link* oldHead = head; head = head->next; delete oldHead; return result; } Stack::~Stack() { require(head == 0, "Stack not empty"); } ///:~ Stack với constructors và destructorStack with constructors and destructor Link::Link( ) constructor chỉ đơn giản khởi data và con trỏ next, vì vậy trong Stack::push( ) có dòng 	Line head = new Link(dat,head); 	không những phân bổ một liên kết mới (sử dụng đối tượng năng động, sáng tạo với các từ khóa mới), mà còn gọn gàng khởi gợi ý cho các liên kết đó. Stack với constructors và destructorStack with constructors and destructor //: C06:Stack3Test.cpp //{L} Stack3 //{T} Stack3Test.cpp // Constructors/destructors #include "Stack3.h" #include "../require.h" #include #include #include using namespace std; int main(int argc, char* argv[]) { requireArgs(argc, 1); // File name is argument ifstream in(argv[1]); assure(in, argv[1]); Stack textlines; string line; // Read file and store lines in the stack: while(getline(in, line)) textlines.push(new string(line)); // Pop the lines from the stack and print them: string* s; while((s = (string*)textlines.pop()) != 0) { cout using namespace std; class Z { int i, j; public: Z(int ii, int jj); void print(); }; Z::Z(int ii, int jj) { i = ii; j = jj; } void Z::print() { cout << "i = " << i << ", j = " << j << endl; } int main() { Z zz[] = { Z(1,2), Z(3,4), Z(5,6), Z(7,8) }; for(int i = 0; i < sizeof zz / sizeof *zz; i++) zz[i].print(); } ///:~ Chú ý rằng nó giống như một hàm dựng được gọi là rõ ràng cho từng đối tượng trong mảng đó. CÁC CONSTRUCTOR MẶC ĐỊNH Default constructors Một constructor mặc định là một hàm không có đối số. Một constructor mặc định được sử dụng để tạo ra một “vanilla object”, nhưng nó cũng rất quan trọng khi nói với trình biên dịch là để tạo ra một đối tượng nhưng không đưa ra bất kỳ chi tiết. Ví dụ, nếu bạn đi struct Y được xác định trước đó và sử dụng nó trong một định nghĩa như thế này 	Y y2[2] = { Y(1) }; trình biên dịch sẽ than phiền rằng nó không thể tìm thấy một constructor mặc định. Đối tượng thứ hai trong mảng đó muốn được tạo ra không có đối số, và đó là nơi trình biên dịch sẽ cho một constructor mặc định. CÁC CONSTRUCTOR MẶC ĐỊNH Default constructors Trong thực tế, nếu bạn chỉ cần định nghĩa một mảng các đối tượng Y: 	Y y3[7]; trình biên dịch sẽ khiếu nại vì nó phải có một constructor mặc định để khởi tạo mọi đối tượng trong mảng vấn đề này cùng xảy ra. nếu bạn tạo một đối tượng cá nhân như thế này: 	Y y4;  nếu bạn có một hàm dựng, trình biên dịch bảo đảm cho xây dựng luôn luôn xảy ra, bất kể tình hình. Các constructor mặc định là quan trọng như vậy là nếu (và chỉ nếu) không có constructor cho một cấu trúc (struct hay class), trình biên dịch sẽ tự động tạo ra cho bạn CÁC CONSTRUCTOR MẶC ĐỊNH Default constructors / / Tự động tạo ra constructor mặc định class V { int i; // private }; // No constructor int main() { V v, v2[10]; } ///:~  Nên xác định constructor một cách đàng hoàn, không nên để trình biên dịch làm việc đó thay bạn. TỔNG KẾTSummary costructor và destructors cho phép bạn khởi tạo phù hợp và đảm bảo sạch (trình biên dịch sẽ không cho phép một đối tượng được tạo ra và bị phá hủy mà không có hàm dựng phù hợp và các cuộc gọi destructor), bạn sẽ có toàn quyền kiểm soát và an toàn khởi tạo tổng hợp thu được bao gồm trong một tĩnh mạch tương tự. -- nó ngăn bạn làm cho những sai lầm khởi điển hình với các uẩn của built-in các loại và làm cho mã của bạn thêm gọn gàng an toàn trong quá trình mã hóa. Là một vấn đề lớn trong C + +. Khởi tạo và dọn dẹp là một phần quan trọng. Exercises  1. Viết một lớp đơn giản gọi là đơn giản với một constructor mà in cái gì để cho bạn biết rằng nó được gọi là. Trong main () làm cho một đối tượng của class của bạn. 2. Thêm một destructor để Exercise 1 mà in ra một thông báo cho bạn biết rằng nó được gọi là. 3. Bài tập 2 sửa đổi để các lớp có chứa một thành viên int. Sửa đổi các constructor để nó phải mất một đối số int rằng các cửa hàng trong thành viên lớp. Cả hai constructor và destructor nên in ra các giá trị int là một phần của thông điệp của họ, vì vậy bạn có thể nhìn thấy các đối tượng khi chúng được tạo ra và tiêu huỷ. 4. Chứng minh rằng destructors vẫn còn gọi là ngay cả khi goto được sử dụng để nhảy ra khỏi một vòng. The End Thực hiện bởi: 	Lâm Thanh Cường 08520526 	Nguyễn Chí Công 08520525 

File đính kèm:

  • pptLập trình hướng đối tượng - Chương 6 Khởi tạo và hủy.ppt
  • rarCStack.rar