Bài giảng Lập trình hướng đối tượng - Chương 9: Tính đa hình

• Con trỏ và Lớp dẫn xuất

• Dẫn nhập các hàm ảo

• Các hàm ảo thuần túy

• Áp dụng đa hình

 Tính đa hình (polymorphism) được hổ trợ bằng hai cách khác nhau trong C++ .

Cách 1, đa hình được hổ trợ khi biên dịch chương trình (compiler) thông qua việc quá

tải các hàm và toán tử.

Cách 2, đa hình được hổ trợ ở thời điểm thực thi chương trình (run-time) thông qua

các hàm ảo. Cách này giúp lập trình viên linh động

 

pdf27 trang | Chuyên mục: C/C++ | Chia sẻ: tuando | Lượt xem: 416 | Lượt tải: 0download
Tóm tắt nội dung Bài giảng Lập trình hướng đối tượng - Chương 9: Tính đa hình, để xem tài liệu hoàn chỉnh bạn click vào nút "TẢI VỀ" ở trên
g có 
liên hệ với nhau nhưng khác nhau, và làm mất đi sự phức tạp giả tạo của hệ thống 
các hoạt động này. 
• Đa hình làm cho mối quan hệ luận lý giữa các hoạt động tương tự nhau được trở 
nên rõ ràng hơn, đo đó nó giúp cho lập trình viên dễ dàng hơn trong việc đọc 
hiểu và bảo trì chương trình. 
Một khi các hoạt động có liên quan với nhau được truy cập bằng duy nhất một giao 
diện, giúp sẽ nhớ hơn. Giao diện đồ hoạ trên hệ điều hành Windows hoặc Macintosh 
là một điển hình. 
2/ Khái niệm về liên kết 
Liên kết (binding) liên quan đến OOP và ngôn ngữ C++. Có hai khái niệm : 
Chương 9 Tính đa hình 286 
• Liên kết sớm (early binding) gắn liền với những biến cố có thể xác định ở thời 
điểm biên dịch chương trình. Đặc biệt, liên kết sớm liên quan đến các gọi hàm 
được xử lý trong lúc biên dịch bao gồm : 
 - Các hàm thông thường 
 - Các hàm được quá tải 
 - Các hàm thành phần không phải là hàm ảo 
 - Các hàm friend 
Tất cả các thông tin về địa chỉ cần thiết cho việc gọi các hàm trên được xác định rõ 
ràng trong lúc biên dịch. 
Ưu điểm : gọi các hàm liên kết sớm là kiểu gọi hàm nhanh nhất. 
Nhược điểm : thiếu tính linh hoạt. 
• Liên kết muộn (late binding) gắn liền với những biến cố xuất hiện trong lúc 
thực thi chương trình (run-time). 
Khi gọi các hàm liên kết muộn, điạ chỉ của hàm được gọi chỉ biết được khi run-time. 
Trong C++, hàm ảo là một đối tượng liên kết muộn. Chỉ khi run-time, hàm ảo được 
truy cập bằng con trỏ của lớp cơ sở, chương trình mới xác định kiểu của đối tượng bị 
trỏ và biết được phiên bản nào của hàm ảo được thực thi. 
Ưu điểm : tính linh hoạt của nó ở thời gian run-time, điều này giúp cho chương trình 
gọn gàng vì không có những đoạn chương trình xử lý các biến cố ngẫu nhiên trong 
khi thực thi. 
Nhược điểm : chậm hơn so với liên kết sớm, do phải qua nhiều giai đoạn trung gian 
kèm theo việc gọi thực thi một hàm liên kết muộn. 
Mỗi loại liên kết đều có những ưu khuyết điểm riêng của nó, nên phải cân nhắc để 
quyết định tình huống thích hợp để sử dụng hai loại liên kết nói trên. 
Ví dụ 4.1 Minh họa tư tưởng "một giao diện cho nhiều phương thức" . 
Chương 9 Tính đa hình 287 
// Demonstrate virtual functons. 
#include 
#include 
#include 
class list { 
public: 
 list *head; // pointer to start of list 
 list *tail; // pointer to end of list 
 list *next; // pointer to next item 
 int num; // value to be stored 
 list() { head = tail = next = NULL; } 
 virtual void store(int i) = 0; 
 virtual int retrieve() = 0; 
}; 
// Create a queue type list. 
class queue : public list { 
public: 
 void store(int i); 
 int retrieve(); 
}; 
void queue::store(int i) 
{ 
 list *item; 
 item = new queue; 
 if(!item) { 
 cout << "Allocation error.\n"; 
 exit(1); 
 } 
 item->num = i; 
 // put on end of list 
Chương 9 Tính đa hình 288 
 if(tail) tail->next = item; 
 tail = item; 
 item->next = NULL; 
 if(!head) head = tail; 
} 
int queue::retrieve() 
{ 
 int i; 
 list *p; 
 if(!head) { 
 cout << "List empty.\n"; 
 return 0; 
 } 
 // remove from start of list 
 i = head->num; 
 p = head; 
 head = head->next; 
 delete p; 
 return i; 
} 
// Create a stack type list. 
class stack : public list { 
public: 
 void store(int i); 
 int retrieve(); 
}; 
void stack::store(int i) 
{ 
 list *item; 
 item = new stack; 
 if(!item) { 
Chương 9 Tính đa hình 289 
 cout << "Allocation error.\n"; 
 exit(1); 
 } 
 item->num = i; 
 // put on front of list for stack-like operation 
 if(head) item->next = head; 
 head = item; 
 if(!tail) tail = head; 
} 
int stack::retrieve() 
{ 
 int i; 
 list *p; 
 if(!head) { 
 cout << "List empty.\n"; 
 return 0; 
 } 
 // remove from start of list 
 i = head->num; 
 p = head; 
 head = head->next; 
 delete p; 
 return i; 
} 
int main() 
{ 
 list *p; 
 // demonstrate queue 
 queue q_ob; 
 p = &q_ob; // point to queue 
 p->store(1); 
Chương 9 Tính đa hình 290 
 p->store(2); 
 p->store(3); 
 cout << "Queue: "; 
 cout retrieve(); 
 cout retrieve(); 
 cout retrieve(); 
 cout << '\n'; 
 // demonstrate stack 
 stack s_ob; 
 p = &s_ob; // point to stack 
 p->store(1); 
 p->store(2); 
 p->store(3); 
 cout << "Stack: "; 
 cout retrieve(); 
 cout retrieve(); 
 cout retrieve(); 
 cout << '\n'; 
 return 0; 
} 
Ví dụ 4.2 Dùng đa hình để xử lý các biến cố ngẫu nhiên. 
 Sử dụng các khai báo và định nghiã lớp ở ví dụ 4.1 . 
int main() 
{ 
 list *p; 
 stack s_ob; 
 queue q_ob; 
Chương 9 Tính đa hình 291 
 char ch; 
 int i; 
 for(i=0; i<10; i++) { 
 cout << "Stack or Queue? (S/Q): "; 
 cin >> ch; 
 ch = tolower(ch); 
 if(ch=='q') 
p = &q_ob; 
 else 
p = &s_ob; 
 p->store(i); 
 } 
 cout << "Enter T to terminate\n"; 
 for(;;) { 
 cout << "Remove from Stack or Queue? (S/Q): "; 
 cin >> ch; 
 ch = tolower(ch); 
 if(ch=='t') break; 
 if(ch=='q') 
p = &q_ob; 
 else 
p = &s_ob; 
 cout retrieve() << '\n'; 
 } 
 cout << '\n'; 
 return 0; 
} 
• Trong HĐH Windows và OS2, thông qua giao diện người dùng giao tiếp với một 
chương trình bằng cách gởi đến chương trình các messages. Những message này 
được phát sinh một cách ngẫu nhiên và chương trình của bạn phải đáp ứng các 
message này mỗi khi nhận được nó. Do đó, đa hình giúp thực thi chương trình rất 
hữu hiệu cho các chương trình được viết để sử dụng trong các HĐH nói trên. 
Ví dụ 4.3 Một chương trình đơn giản nhất trên Windows, xuất ra màn hình 
Chương 9 Tính đa hình 292 
một khung cửa sổ chứa nội dung " Hello, Windows 98 ! " 
#include 
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; 
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, 
 PSTR szCmdLine, int iCmdShow) 
{ 
 static TCHAR szAppName[] = TEXT ("HelloWin") ; 
 HWND hwnd ; 
 MSG msg ; 
 WNDCLASS wndclass ; 
 wndclass.style = CS_HREDRAW | CS_VREDRAW ; 
 wndclass.lpfnWndProc = WndProc ; 
 wndclass.cbClsExtra = 0 ; 
 wndclass.cbWndExtra = 0 ; 
 wndclass.hInstance = hInstance ; 
 wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; 
 wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; 
 wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ; 
 wndclass.lpszMenuName = NULL ; 
 wndclass.lpszClassName = szAppName ; 
 if (!RegisterClass (&wndclass)) { 
 MessageBox (NULL, TEXT ("This program requires Windows NT!"), 
 szAppName, MB_ICONERROR) ; 
 return 0 ; 
 } 
 hwnd = CreateWindow (szAppName, // window class name 
 TEXT ("The Hello Program"), // window caption 
 WS_OVERLAPPEDWINDOW, // window style 
 CW_USEDEFAULT, // initial x position 
 CW_USEDEFAULT, // initial y position 
 CW_USEDEFAULT, // initial x size 
Chương 9 Tính đa hình 293 
 CW_USEDEFAULT, // initial y size 
 NULL, // parent window handle 
 NULL, // window menu handle 
 hInstance, // program instance handle 
 NULL) ; // creation parameters 
 ShowWindow (hwnd, iCmdShow) ; 
 UpdateWindow (hwnd) ; 
 while (GetMessage (&msg, NULL, 0, 0)) { 
 TranslateMessage (&msg) ; 
 DispatchMessage (&msg) ; 
 } 
 return msg.wParam ; 
} 
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM 
wParam, LPARAM lParam) 
{ 
 HDC hdc ; 
 PAINTSTRUCT ps ; 
 RECT rect ; 
 switch (message) 
 { 
 case WM_CREATE : 
 PlaySound (TEXT("hellowin.wav"), NULL, SND_FILENAME | 
SND_ASYNC) ; 
 return 0 ; 
 case WM_PAINT : 
 hdc = BeginPaint (hwnd, &ps) ; 
 GetClientRect (hwnd, &rect) ; 
 DrawText (hdc, TEXT (" Hello, Windows 98 ! "), -1, &rect, 
Chương 9 Tính đa hình 294 
 DT_SINGLELINE | DT_CENTER | DT_VCENTER) ; 
 EndPaint (hwnd, &ps) ; 
 return 0 ; 
 case WM_DESTROY : 
 PostQuitMessage (0) ; 
 return 0 ; 
 } 
 return DefWindowProc (hwnd, message, wParam, lParam) ; 
} 
Bài tập IV 
1. Thêm vào chương trình ở ví dụ 4.1 một kiểu danh sách liên kết, là loại danh sách 
có chức năng xếp các phần tử theo thứ tự tăng dần mỗi khi thêm phần tử mới vào 
danh sách. Đặt tên cho lớp này là sorted thừa kế lớp cơ sở list. 
Lớp sorted chứa hai hàm chung là 
- void store(int i) có chức năng thêm phần tử mới vào danh sách sao cho chúng có 
thứ tự tăng dần. 
- và int retrieved() có chức năng hiển thị các phần tử trong danh sách. 
2. Hãy viết một chương trình có áp dụng tính đa hình. 
Bài tập chương 9 
Chương 9 Tính đa hình 295 
1. Xét đoạn chương trình sau đây. Tìm lỗi và giải thích tại sao ? 
class base { 
public: 
 virtual int f(int a) = 0; 
 // ... 
}; 
class derived : public base { 
public: 
 int f(int a, int b) { return a*b; } 
 // ... 
}; 
2. Trình bày sự khác nhau giữa hàm ảo và quá tải hàm. 
3. Viết chương trình bổ sung vào ví dụ 4.1 chương 9, bằng cách quá tải hai toán tử + 
và toán tử -- vào lớp dẫn xuất stack và queue . 
Toán tử + thêm một phần tử vào danh sách 
 stack operator + (int i) ; 
 queue operator + (int i) ; 
và toán tử -- lấy một phần tử ra khỏi danh sách. 
 int operator -- (int unused) ; // cho cả stack và queue . 
4. Hãy sửa đổi một số ví dụ về quá tải hàm trong các chương trước, sao cho có thể 
chuyển đổi các hàm được quá tải thành các hàm ảo ? 

File đính kèm:

  • pdfbai_giang_lap_trinh_huong_doi_tuong_tap_1_chuong_9_tinh_da_h.pdf