Lập trình hướng đối tượng - Initialization & Cleanup

MỤC LỤC

Giới thiệu . . . . 1

1. GUARANTEED INITIALIZATION WITH THE CONSTRUCTOR . 3

2. GUARANTEED CLEANUP WITH THE DESTRUCTOR . . 7

3. STACK WITH CONSTRUCTOR & DESTRUCTOR . . 9

4. COPY CONSTRUCTOR . . . 11

5. ELIMINATION OF DEFINITION BLOCK . . 12

6. FOR LOOPS . . . . 14

7. STORAGE ALLOCATION . . . 15

8. AGGREGATE INITIALIZATION . . . 16

9. DEFAULT CONSTRUCTOR. . . 18

10. SUMMARY. . . . 19

Reference . . . . 20

pdf21 trang | Chuyên mục: Lập Trình Hướng Đối Tượng | Chia sẻ: dkS00TYs | Lượt xem: 1372 | Lượt tải: 1download
Tóm tắt nội dung Lập trình hướng đối tượng - Initialization & Cleanup, để xem tài liệu hoàn chỉnh bạn click vào nút "TẢI VỀ" ở trên
Dễ dàng nhận thấy rằng, với cách khai báo biến như trên, đoạn code dường như trực
quan hơn và dẽ hiểu hơn nhiều. Hai biến y và biến test_p không còn phải cứng nhắc khai
báo ở đầu scope nữa. Với C++, mọi thứ bây giờ trở nên tiện lợi hơn với lập trình viên.
6. FOR LOOPS.
Một sự mở rộng mới từ sự uyển chuyển của việc khai báo biến linh hoạt ở C++ là
việc đưa vào tính năng định nghĩa những biến xác định ngay bên trong cấu trúc vòng lặp
for, là cấu trúc lặp hay được sử dụng nhất. Ví dụ sau sẽ minh họa rõ hơn cho điều này.
1 for(int j = 0; j 4
2 {
3 cout << "j = " << j << endl;
4 }
5 for(int i = 0; i 10
6 {
7 cout << "i = " << i << endl;
8 for( int k=0;k<10;k++)
9 cout << "k = " << k << endl;
10 }
Từ đoạn code minh họa trên, ta dễ dàng nhận thấy rằng các biến cục bộ i,j được khai
báo ngay trong cấu trúc for, đây là tính năng mới mà ngôn ngữ C chuẩn không hỗ trợ.
Cũng nhờ đó mà các lập trình viên có thể nhanh chóng khai báo cho trình biên dịch biết
những biến tạm nào đó sẽ được sử dụng trong vòng lặp for mà không cần quan tâm tới
việc phải định nghĩa các biến này trước khi sử dụng trong vòng lặp for như họ đã từng
khi làm việc với C chuẩn trước kia. Tuy nhiên, ta cần lưu ý kỹ 1 tính chất cho tính năng
mới này đó là các biến tạm được khai báo trong cấu trúc vòng lặp for nào sẽ chỉ có ý
nghĩa(tồn tại) trong phạm vi cục bộ của cấu trúc vòng lặp for đó mà thôi(kết thúc vòng
lặp, các biến này sẽ được hủy bỏ tự động), nếu ta cố truy xuất các biến tạm đó từ bên
ngoài vòng lặp for, bug về undefined variable có thể xảy ra.
15
7. STORAGE ALLOCATION.
Với việc một biến có thể khai báo bất kỳ nơi đâu trong phạm vi “{}”(scope), nó cũng
tương tự rằng tác vụ cấp phát vùng nhớ để lưu trữ 1 biến bất kỳ sẽ không được thực thi
cho tới khi biến đó được định nghĩa 1 cách tường minh tại 2 vị trí nào đó trong scope. Về
thực tế, điều này cũng giống như việc trình biên dịch sẽ theo như cách thức làm việc của
C đó là cấp phát vùng lưu trữ cho các biến sẽ được sử dụng trong scope “{}” ngay sau
dấu mở “{“, có chăng chỉ là sự linh hoạt về vị trí khai báo biến trong scope mà thôi. Với
lập trình viên, điều này dường như cũng không quan trọng quan trọng bởi vì bạn không
thể truy xuất vào vùng lưu trữ của biến-đối tượng đó tới khi nào nó được định nghĩa 1
cách tường minh cho trình biên dịch. Do đó, ta cần phải hiểu rõ rằng, mặc dù việc cấp
phát vùng nhớ cho các biến-đối tượng là được thực hiện ở đầu scope, thế nhưng, hàm
constructor của các biến-đối tượng tương ứng sẽ không được gọi thực thi cho tới khi nào
các biến-đối tượng đó được định nghĩa 1 cách tường minh. Bên cạnh những điều đã phân
tích ở trên, trình biên dịch C++ còn bảo đảm cho thao tác initialization 1 đối tượng mới là
an toàn nếu lập trình viên đặt câu lệnh khai báo một đối tượng mới vào trong 1 mệnh đề
điều kiện như cấu trúc if-else, switch hoặc thậm chí là một câu lệnh goto để jump tới 1
dòng lệnh bất kỳ.
class point
{
private:
int x;
public:
point(int px) { x=px; }
~point() {}
};
void main()
{
int x;
printf("Nhap vao gia tri x=");
scanf("%d",&x);
if(x>10)
goto label1;
new_class test1; //error initialization of 'test1' is skipped by 'goto label1'
label1:switch(x)
{
16
case 1:
new_class test2; //error initialization of 'test2' is skipped by 'case' label
break;
case 2:
new_class test3;
break;
}
}
Khi thử compile đoạn code minh họa trên với Visual C++ 6.0, ta nhận được 2 error
khi ta cố định nghĩa các biến test1 và test2 ở những vị trí nhạy cảm, nơi mà nó có thể dễ
dàng bị bỏ qua, và do đó, hàm constructor cũng sẽ không được gọi để thực thi. Ở đây, ta
cũng phải hiểu rõ rằng, tất cả những quá trình cấp phát được đề cập ở trên đều hàm ý là
trên stack. Nếu muốn cấp phát lưu trữ biến-đối tượng trên heap, ta có thể sử dụng con trỏ
kết hợp với toán tử new để thực hiện điều đó.
8. AGGREGATE INITIALIZATION.
Khởi tạo tập hợp(kết hợp) là một khái niệm trong C, là tính năng cho phép lập trình
viên có thể kết hợp khai báo nhiều biến-đối tượng trên cùng 1 dòng lệnh và có thể được
quản lý dưới 1 object chung nhất. Một mảng là 1 sự kết hợp của nhiều đối tượng cùng
kiểu có thể được khởi tạo theo tính năng này.
Với C++, trình biên dịch làm cho tính năng này có thể hỗ trợ tốt nhất cho lập trình
viên và cũng cải thiện để làm cho nó an toàn hơn khi được sử dụng. Khi tiến hành tạo
mới một đối tượng theo kiểu tập hợp, điều lập trình viên cần làm là tạo mới 1 chỉ định để
báo cho trình biên dịch biết rằng cần phải quản lý quá trình khởi tạo cho các biến phần tử
trong tập hợp đó. Thao tác tạo 1 mảng mới với kiểu dữ liệu là built-in theo kiểu tập hợp
thì đơn giản như sau:
int a[3] = { 3, 4, 5};
Từ ví dụ trên, ta dễ dàng rút ra được quy tắc để khai báo 1 biến mảng theo kiểu tập
hợp đó là: các giá trị của các phần tử trong mảng thì được khai báo trong cặp dấu {}, vị
trí của các giá trị cũng là vị trí tương ứng trong mảng, và các giá trị cách nhau bằng “,”.
Thế nhưng, nếu ta cố khai báo các phần tử trong tập hợp mà số lượng các phần tử nhiều
hơn kích thước mảng đã định nghĩa ở bên trái thì trình biên dịch sẽ báo lỗi. Vậy, câu hỏi
đặt ra là nếu như số lượng các phần tử trong khai báo tập hợp là ít hơn kích thước mảng
đã khai báo như ví dụ sau thì sẽ như thế nào?
17
int a[3] = { 3, 4};
Giải pháp mà cả C và C++ chọn giải quyết là: sẽ set giá trị 0 cho những phần tử
không được định nghĩa ở vị trí tương ứng trong khai báo tập hợp ở vế phải. Điều đó có
nghĩa rằng, với ví dụ trên, thì a[2] sẽ nhận giá trị 0, trong khi a[0]=3 và a[1]=4.
Ngoài phương pháp khai báo mảng như trên,có một phương pháp khác ngắn gọn hơn
và cũng tiện lợi hơn mà các lập trình viên có thể sử dụng đó là “automatic counting”. Khả
năng này cho phép trình biên dịch tự động xác định kính thước tương ứng cho mảng khi
duyệt qua tập hơp tương ứng các phần tử cho mảng ở vế phải. Nếu cần biết thông tin về
số thành phần của mảng, ta có thể sử dụng công thức sizeof(object)/sizeof(*object) để xác
định.
int a[] = { 3, 4, 5, 6, 7};
int nums=sizeof(a)/sizeof(*a);
for(int i=0;i<nums;i++) printf(“a[%d]=%d\n”,i,a[i]);
Bên cạnh mảng, thì struct cũng là 1 dạng của object tập hợp. Cấu trúc và nguyên tắc
khai báo 1 mảng các struct thì cũng hoàn toàn tương tự như việc khai báo 1 mảng thuộc
kiểu dữ liệu built-in.
typedef struct
{
int x;
int y;
}point;
void main()
{
point pt1={1,2}; //pt1.x=1 ; pt1.y=2;
point ptarr[3]={{1,3},{4,5}}; //ptarr[2].x=0; ptarr[2].y=0;
}
Trong trường hợp ta muốn khai báo theo phương pháp tập hợp 1 mảng các struct hoặc
mảng các đối tượng thuộc 1 class nào đó đã được xây dựng hàm constructor, thì cách tốt
nhất là ta nên gọi thực thi constructor để tạo ra các giá trị hằng rồi gán các giá trị hằng
này vào trong tập hợp như sau:
class point
{
18
private:
int x;
int y;
public:
point(int tx,int ty){ x=tx; y=ty};
~point(){}
};
void main()
{
point ptarr[3]={point(1,3),point(4,5),point(3,6)};
}
Khi khai báo 1 mảng các đối tượng point theo ví dụ trên, thì hàm constructor của lớp
point sẽ được gọi 3 lần rồi gán các giá trị đó vào tập hợp bên phải, là cơ sở để khởi tạo
mảng từ tập hợp được xây dựng ở bên phải thông qua việc gọi hàm constructor 1 cách
tường minh cho từng phần tử.
9. DEFAULT CONSTRUCTOR.
Hàm khởi tạo mặc định là hàm khởi tạo không nhận bất kỳ tham số nào và cũng
không thực thi bất kỳ tác vụ nào trong thân hàm , đồng thời cũng là hàm mà trình biên
dịch sẽ tự động phát sinh nếu không tìm thấy bất kỳ hàm constructor nào được xây dựng
trong class. Khi 1 hàm constructor được định nghĩa trong class, thì hàm default
constructor sẽ không được trình biên dịch phát sinh nữa. Trong nhiều trường hợp, thì hàm
default constructor chiếm 1 vai trò khá quan trọng. Một minh chứng điển hình nhất cho
tính quan trọng của hàm default constructor đó là việc khai báo một mảng các đối tượng
cho class như sau:
point a[5];
Câu lệnh trên hàm ý rằng lập trình viên muốn cấp phát vùng nhớ để lưu trữ 5 biến
point, điều này cũng đồng nghĩa với việc trình biên dịch sẽ gọi thực thi 5 lần hàm
constructor không nhận tham số đầu vào(thông thường là hàm default constructor). Nếu
chẳng may lập trình viên chỉ xây dựng các hàm constructor có nhận tham số đầu vào cho
class thì chắc chắn trình biên dịch sẽ báo lỗi với câu lệnh trên với 1 lý do đơn giản rằng
trình biên dịch không tìm thấy hàm constructor thích hợp để gọi thực thi tương ứng.
19
Một ví dụ khác minh họa cho tính cần thiết của hàm default constructor đó là thao tác
khai báo mảng theo phương pháp tập hợp như ví dụ sau:
point a[2]={ point(3,5) };
Với việc khai báo như trên, trình biên dịch sẽ hiểu rằng phần tử a[1] sẽ nhận giá trị từ
việc gọi thực thi hàm constructor không nhận tham số đầu vào của class point. Trong
trường hợp class point không xây dựng bất kỳ hàm constructor nào, thì trình biên dịch sẽ
phát sinh rồi gọi thực thi hàm default constructor đó.
10. SUMMARY.
Qua những đề mục đã trình bày ở trên, ta có thể phần nào nắm được những tính năng
mạnh mẽ mà C++ hỗ trợ cho các tác vụ initialization cũng như cleanup đối tượng. Với
C++, những thao tác initialization & cleanup trở nên an toàn và tiện lợi hơn bao giờ
hết. Bởi lẽ, với việc xây dựng constructor và destructor, C++ bảo đảm những thao tác
initialization và cleanup luôn được thực hiện 1 cách đúng đắn và thích hợp nhất (trình
biên dịch không cho phép một đối tượng được tạo mới hoặc hủy mà không gọi thực
thi hàm constructor và destructor tương ứng). Bên cạnh đó là những tính năng khác
như: tham số mặc định, copy constructor, khởi tạo mảng đối tượng theo dạng tập
hợp,v.v… C++ thực sự mang lại cho các lập trình viên khái niệm của “an toàn và tiện
lợi”.
REFERENCE:
20
 Chapter 6 – Initialization and cleanup - Thinking in C++ - Vol 1 – Bruce
Eckel.
 The C programming language – Brian W.Kernighan , Dennis M.Ritchie.
 C++ - The complete reference – Third Edition – Herb Schildt.
 Lập trình hướng đối tượng với C++ - Phạm Văn Ất.

File đính kèm:

  • pdfLập trình hướng đối tượng - Initialization & Cleanup.pdf