Lập trình hướng đối tượng trong C++ - Chương 6: Khởi tạo và hủy
Cả stash và Stack các lớp được định nghĩa trước đây có một chức năng gọi là initialize( ), mà theo tên của nó gợi ý rằng nó nên được gọi là trước khi sử dụng các đối tượng trong bất kỳ cách nào khác. Thật không may, điều này có nghĩa là các cilent programmar phải đảm bảo khởi động tốt. client programmer dễ bị bỏ lỡ các chi tiết như khởi tạo trong Headlong của họ vội vàng để làm thư viện tuyệt vời của bạn giải quyết vấn đề của họ. Trong C + +, khởi tạo là quá quan trọng để lại cho các cilent programmar. Nhà thiết kế lớp học có thể đảm bảo khởi của mọi đối tượng bằng cách cung cấp một chức năng đặc biệt gọi là constructor . 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, trước khi trình khách hàng có thể có được bàn tay của họ về đối tượng. Các cuộc gọi ngay cả hàm dựng không phải là một lựa chọn cho các client programmer; nó được thực hiện bởi trình biên dịch tại điểm đối tượng được xác định.
goặc nhọn. Đối với một mảng xây dựng trong các loại này khá đơn giản: int a[5] = { 1, 2, 3, 4, 5 }; Nếu bạn cố gắng cung cấp cho initializers hơn đó là những yếu tố mảng, trình biên dịch cho một thông báo lỗi. Nhưng những gì xảy ra nếu bạn cho initializers ít hơn? Ví dụ: int b[6] = {0}; Ở đây, trình biên dịch sẽ sử dụng initializer đầu tiên cho các phần tử mảng đầu tiên, và sau đó sử dụng số không cho tất cả các yếu tố mà không initializers. Thông báo khởi hành vi này không xảy ra nếu bạn định nghĩa một mảng mà không có một danh sách các initializers. Vì vậy, các biểu hiện ở trên là một cách gọn gàng để khởi tạo một mảng về không, mà không cần sử dụng cho vòng lặp, và không có khả năng xảy ra một off-by-một trong những lỗi (Tùy thuộc vào trình biên dịch, nó cũng có thể hiệu quả hơn hơn cho vòng lặp. ) A viết tắt cho mảng thứ hai là tự động đếm, mà trong đó bạn cho phép trình biên dịch xác định kích thước của mảng đó dựa trên số lượng initializers: int c[] = { 1, 2, 3, 4 }; Bây giờ nếu bạn quyết định thêm một yếu tố để mảng đó, bạn chỉ cần thêm một initializer. Nếu bạn có thể đặt mã của bạn lên vì vậy nó cần phải được thay đổi trong chỉ có một chỗ, bạn làm giảm cơ hội sai sót trong quá trình sửa đổi. Nhưng làm thế nào để bạn xác định kích thước của mảng đó? Những biểu hiện sizeof c / sizeof * c (kích thước của toàn bộ mảng chia cho kích thước của phần tử đầu tiên) như thế với trick trong một cách mà không cần phải được thay đổi nếu kích thước mảng changes5: for(int i = 0; i < sizeof c / sizeof *c; i++) c[i]++; Bởi vì cấu trúc cũng được tập hợp, chúng có thể được khởi tạo trong một thời trang tương tự. Bởi vì một C-style struct có tất cả các thành viên công chúng của mình, chúng có thể được phân công trực tiếp: struct X { int i; float f; char c; }; X x1 = { 1, 2.2, 'c' }; Nếu bạn có một mảng các đối tượng như vậy, bạn có thể khởi tạo cho họ bằng cách sử dụng một bộ lồng nhau của các dấu ngoặc nhọn cho từng đối tượng: X x2[3] = { {1, 1.1, 'a'}, {2, 2.2, 'b'} }; Ở đây, đối tượng thứ ba là khởi tạo không. Nếu bất kỳ thành viên dữ liệu được tư nhân (mà thường là trường hợp cho một lớp học được thiết kế tốt trong C + +), hoặc thậm chí nếu tất cả mọi thứ của công chúng, nhưng có một constructor , những thứ có khác nhau. Trong ví dụ trên, initializers được phân công trực tiếp vào các yếu tố của tổng hợp, nhưng constructor là một cách để buộc khởi xảy ra thông qua một giao diện chính thức. Ở đây, các constructor phải được gọi là thực hiện khởi. Vì vậy, nếu bạn có một cấu trúc trông như thế này, 5 Trong Tập 2 của cuốn sách này (một cách tự do có sẵn tại www.BruceEckel.com), bạn sẽ thấy một tính gọn gàng hơn kích thước của một mảng bằng cách sử dụng các mẫu. struct Y { float f; int i; Y(int a); }; Bạn phải chỉ ra các cuộc gọi constructor . Phương pháp tốt nhất là một trong những rõ ràng như sau: Y y1[] = { Y(1), Y(2), Y(3) }; Bạn nhận ba đối tượng và ba cuộc gọi constructor . Bất cứ lúc nào bạn có một constructor , cho dù đó là một cấu trúc với tất cả các thành viên công cộng hoặc một lớp học với các dữ liệu cá nhân thành viên, tất cả các khởi phải qua constructor , thậm chí nếu bạn đang sử dụng khởi tạo tổng hợp. Dưới đây là một ví dụ thứ hai đối số hiển thị nhiều constructor : //: C06:Multiarg.cpp // Multiple constructor arguments // with aggregate initialization #include 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 constructor được gọi là rõ ràng cho từng đối tượng trong mảng đó. CONSTRUCTOR MẶC ĐỊNH Một constructor mặc định là một trong đó có thể được gọi là không có đối số. Một constructor mặc định được sử dụng để tạo ra một đối tượng vanilla "," 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. 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; Hãy nhớ rằng, nếu bạn có một constructor , 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 lớp), trình biên dịch sẽ tự động tạo ra một cho bạn. Vì vậy, công trình này: / /: C06: AutoDefaultConstructor .cpp / / Tự động tạo ra constructor mặc định class V { int i; // private }; // No constructor int main() { V v, v2[10]; } ///:~ Nếu bất kỳ constructor được xác định, tuy nhiên, và không có constructor mặc định, các trường hợp của V ở trên sẽ tạo ra biên dịch lỗi thời. Bạn có thể nghĩ rằng trình biên dịch, tổng hợp constructor nên làm một số khởi tạo thông minh, như đặt tất cả các bộ nhớ cho các đối tượng để bằng không. Nhưng nó không - mà có thể gắn thêm trên không nhưng có thể kiểm soát của lập trình viên. Nếu bạn muốn nhớ được khởi tạo về không, bạn phải làm điều đó cho mình bằng cách viết các constructor mặc định rõ ràng Mặc dù trình biên dịch sẽ tạo ra một constructor mặc định cho bạn, hành vi của trình biên dịch. Tổng hợp constructor là rất hiếm khi những gì bạn muốn. Bạn nên xử lý tính năng này như là một mạng lưới an toàn, nhưng ít sử dụng nó. Nói chung, bạn nên xác định constructor của bạn một cách rõ ràng và không cho phép trình biên dịch để làm điều đó cho bạn. TỔNG KẾT Dường như xây dựng các cơ chế cung cấp bởi C + +, nên cung cấp cho bạn một gợi ý mạnh mẽ về tầm quan trọng quan trọng được đặt trên khởi tạo và dọn dẹp trong ngôn ngữ. Theo Stroustrup đã được thiết kế C + +, một trong những quan sát đầu tiên anh được về năng suất trong C là một phần quan trọng của các vấn đề lập trình được gây ra bởi khởi không thích hợp của các biến. Những vấn đề về các loại lỗi là khó tìm, và tương tự áp dụng cho sạch không đúng cách. Bởi vì constructor 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ó constructor 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 Giải pháp cho các bài tập được chọn có thể được tìm thấy trong các tài liệu điện tử của tư duy trong C + + Annotated Solution Guide, sẵn sàng cho một khoản phí nhỏ từ www.BruceEckel.com. 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 lớp học 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 vòng một. 5. Viết cho vòng hai đó in ra các giá trị từ số không đến 10. Năm đầu tiên, xác định truy cập vòng trước khi cho vòng lặp, và trong lần thứ hai, xác định truy cập lặp trong biểu thức kiểm soát của cho vòng lặp. Đối với phần thứ hai của tập thể dục này, sửa đổi danh tánh trong lần thứ hai cho vòng lặp để nó như là cùng tên với vòng lặp để truy cập đầu tiên và xem những gì trình biên dịch của bạn không. 6. Sửa đổi Handle.h, Handle.cpp, và UseHandle.cpp tập ở cuối chương 5 để sử dụng constructor và destructors. 7. Sử dụng tổng hợp để khởi tạo một mảng của đôi trong đó bạn chỉ định kích thước của mảng đó nhưng không cung cấp đủ các yếu tố. In ra mảng này bằng cách sử dụng sizeof để xác định kích thước của mảng. Bây giờ tạo một mảng của đôi bằng cách sử dụng khởi tạo tổng hợp và đếm tự động. In ra mảng. 8. Sử dụng tổng hợp khởi tạo một mảng các đối tượng chuỗi. Tạo một Stack để chứa các chuỗi s và bước qua các mảng của bạn, đẩy mỗi chuỗi ngày Stack của bạn. Cuối cùng, pop chuỗi s off Stack của bạn và in mỗi một. 9. Chứng minh tính tự động và khởi tạo tổng hợp với một mảng của các đối tượng của lớp bạn đã tạo trong tập 3. Thêm một chức năng thành viên cho rằng lớp học mà in một tin nhắn. Tính toán kích thước của mảng và di chuyển qua nó, gọi hàm thành viên mới của bạn. 10. Tạo một lớp học mà không có bất kỳ nhà thầu, và cho thấy rằng bạn có thể tạo đối tượng với constructor mặc định. Bây giờ tạo một constructor nondefault (một với một đối số) cho lớp, và thử biên dịch lại. Giải thích những gì xảy ra. Một trong những cuốn sách của các tác giả bạn có thể tham khảo: - Lập trình hướng đối tượng sử dụng C++ tác giả Phạm Văn Ất - Lập Trình hướng Đối Tượng Với C++ tác giả Ths. Nguyễn Đình Nam - Lập Trình Hướng Đối Tượng Với C++ tác giả Lê Đăng Hưng - 247 Bài Tập Lập Trình Hướng Đối TượngVới C++ (Tái Bản Lần 3) tác giả Lê Minh Trung - Bài Tập Lập Trình Hướng Đối Tượng Với C++ tác giả Nguyễn Thanh Thuỷ Trân trọng giới thiệu
File đính kèm:
- Lập trình hướng đối tượng trong C++ - Chương 6 Khởi tạo và hủy.doc
- CStack.rar