1. Trang chủ
  2. » Công Nghệ Thông Tin

Tính đa hình

27 712 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 27
Dung lượng 53,43 KB

Nội dung

Bài giảng lập trình hướng đối tượng - Thầy Cường Học viện bưu chính viễn thông TP HCM

Trang 1

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

Trang 2

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

1/ Khái niệm

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 hơn

• Cơ sở của hàm ảo và đa hình khi thực thi chương trình là các con trỏ của lớp dẫn xuất

Chương 3 có khảo sát về con trỏ, một đặc tính mới của con trỏ sẽ được khảo sát

trong chương này Nếu p là một con trỏ tới lớp cơ sở, thì có thể sử dụng p để trỏ tới

bất kỳ lớp nào được suy ra từ lớp cơ sở

Chẳng hạn, có hai lớp cơ sở base và lớp dẫn xuất derived kế thừa base, các phát biểu

sau đều đúng

base *p; // base class pointer

base base_ob; // object of type base

derived derived_ob; // object of type derived

// p can, of course, point to base objects

p = &base_ob; // p points to base object

// p can also point to derived objects without error

p = &derived_ob; // p points to derived object

Một con trỏ của lớp cơ sở có thể trỏ tới bất kỳ lớp dẫn xuất nào của lớp cơ sở mà

không gây ra báo lỗi khác kiểu Song chỉ có thể truy cập được các thành phần mà lớp

dẫn xuất được kế thừa từ lớp cơ sở Bởi vì con trỏ của lớp cơ sở chỉ biết lớp cơ sở mà thôi, nó không biết gì những thành phần được thêm vào bởi lớp dẫn xuất

Trang 3

Một con trỏ của lớp dẫn xuất không thể dùng để truy cập một đối tượng của lớp

cơ sở (Việc sử dụng linh hoạt kiểu có thể dùng để khắc phục hạn chế nói trên, nhưng nó không được khuyến khích sử dụng)

Các phép toán số học trên con trỏ liên quan đến kiểu dữ liệu mà con trỏ đó được

khai báo để trỏ đến Do đó, nếu con trỏ đến một đối tượng lớp dẫn xuất, rồi tăng nội

dung con trỏ lên 1 Điều này không làm cho con trỏ chỉ đến đối tượng mới của lớp

dẫn xuất, mà nó sẽ chỉ đến đối tượng mới của lớp cơ sở

Ví dụ 1.1 Dùng con trỏ của lớp cơ sở để truy cập đến lớp dẫn xuất

// Demonstrate pointer to derived class

base *p; // pointer to base type

base b_ob; // object of base

derived d_ob; // object of derived

// use p to access base object

p = &b_ob;

Trang 4

p->setx(10); // access base object

cout << "Base object x: " << p->getx() << '\n';

// use p to access derived object

p = &d_ob; // point to derived object

p->setx(99); // access derived object

// can't use p to set y, so do it directly

d_ob.sety(88);

cout << "Derived object x: " << p->getx() << '\n';

cout << "Derived object y: " << d_ob.gety() << '\n';

Khai báo hàm ảo bắt đầu bằng từ khoá virtual Một lớp có chứa hàm ảo được kế

thừa, lớp dẫn xuất sẽ tái định nghiã hàm ảo đó cho chính mình

Các hàm ảo triển khai ý tưởng chủ đạo của đa hình là "một giao diện cho nhiều

phương thức " Hàm ảo bên trong một lớp cơ sở định nghiã hình thức giao tiếp đối

với hàm đó

Việc tái định của hàm ảo ở lớp dẫn xuất là thi hành các tác vụ của hàm liên quan đến

chính lớp dẫn xuất đó Nói cách khác, tái định các hàm ảo chính là tạo ra các phương thức cụ thể Hàm ảo tái định ở lớp dẫn xuất không cần sử dụng từ khoá virtual

Nguyên lý làm việc của đa hình trong khi thực thi chương trình :

Trang 5

Hàm ảo được gọi thực thi giống như các hàm thành phần bình thường của lớp Tuy nhiên, khi gọi hàm ảo bằng con trỏ, việc hổ trợ tính đa hình trong khi thực thi chương trình sẽ xảy ra

Khi một con trỏ trỏ đến một lớp dẫn xuất có chứa hàm ảo và hàm ảo này được gọi bằng con trỏ thì trình biên dịch sẽ xác định phiên bản nào của hàm đó sẽ được thực thi Do đó nếu có hai hay nhiều lớp dẫn xuất của một lớp cơ sở nào đó, và chúng đều có chứa hàm ảo, thì con trỏ của lớp cơ sở có thể trỏ đến các đối tượng khác nhau của lớp dẫn xuất nói trên, tức là có thể gọi đến nhiều phiên bản khác nhau của các hàm ảo

Một lớp có chứa hàm ảo được gọi là lớp đa hình

Trang 6

2/ Hàm ảo và quá tải hàm

Giải thích kết qủa chương trình ?

Using base version of func() : 10 Using derived1's version of func() : 100 Using derived2's version of func() : 20

Trang 7

Việc tái định hàm ảo trong một lớp dẫn xuất có tương tự như quá tải hàm không ?

Câu trả lời là không

Quá tải hàm Hàm ảo

Số lượng đối số Cho phép khác biệt Phải giống nhau

Kiểu dữ liệu của đối số Cho phép khác biệt Phải giống nhau

Hàm thành phần của lớp Không bắt buộc Bắt buộc

Vị trí

Việc tái định hàm ảo trong một lớp dẫn xuất còn được gọi là gán thứ tự ưu tiên cao

hơn cho hàm đó

3/ Các hàm ảo được phân cấp theo thứ tự kế thừa

Nếu lớp dẫn xuất không tái định hàm ảo nào đó thì lớp này sẽ sử dụng phiên bản hàm của lớp cơ sở

Trang 8

// This example illustrates how a virtual function can be used to respond to random

// events occurring at run time

Keát quûa chöông trình

Using base version of func() : 10 Using derived1's version of func() : 100 Using base version of func() : 10

Trang 10

if( ( j % 2) ) p = &d_ob1; // if odd use d_ob1

else p = &d_ob2; // if even use d_ob2

5/ Sử dụng hàm ảo để triển khai cách thức giao diện

Trang 11

void getdim(double &d1, double &d2) {

d1 = dim1;

d2 = dim2;

}

virtual double getarea() {

cout << "You must override this function\n";

Trang 12

virtual void shownum() { cout << i << '\n';}

Trang 13

distance (double f) { d = f;}

virtual void trav_time() {

// define here

} };

Tạo hàm ảo trav_time() của lớp distance xuất ra khoảng thời gian cần thiết để đi qua khoảng cách này Giả sử rằng đơn vị chiều dài là mile và vận tốc di chuyển là 60 mile/hours

Hãy tạo lớp dẫn xuất metric từ lớp distance, với hàm ảo trav_time() in ra khoảng thời gian cần thiết để đi qua khoảng cách trên, tuy nhiên lúc này đơn vị chiều dài là

km và vận tốc là 100km/giờ

III/ Các hàm ảo thuần túy (pure virtual function)

Một trường hợp khá phổ biến khi lớp cơ sở tự nó không phải là một lớp hoàn chỉnh,

lúc đó hàm ảo được khai báo giữ chỗ chứ không thực hiện công việc cụ thể Lớp cơ sở này chỉ cung cấp một bộ khung gồm các hàm và biến và để dành cho các lớp dẫn xuất các phần định nghĩa còn lại Các lớp dẫn xuất phải tái định tất cả các hàm ảo khai báo trong lớp cơ sở đó Để đảm bảo cho điều này, C++ hổ trợ một công cụ gọi là hàm ảo thuần túy

Hàm ảo thuần túy không có một định nghiã nào liên quan đến lớp cơ sở Nó chỉ có dạng hàm mà thôi, cách khai báo

virtual <type> func-name(arg-list) = 0 ;

Hàm được gán trị zero với mục đích thông báo cho trình biên dịch biết là không có

gì trong hàm là liên quan đến lớp cơ sở

Khi hàm ảo là một hàm ảo thuần túy, nó buộc các lớp dẫn xuất phải tái định nó, nếu không trình biên dịch sẽ báo lỗi lúc biên dịch chương trình

Nếu một lớp có chứa hàm ảo thuần túy, lớp đó được gọi là lớp trừu tượng

Lớp trừu tượng được tạo ra với mục đích phải được kế thừa, không được và không thể tạo ra để tồn tại đơn độc

Trang 14

Tuy nhiên, có thể tạo ra một con trỏ đến lớp trừu tượng bởi vì điều này cần thiết để

hổ trợ cho đa hình trong khi run-time Điều này cũng cho phép tham chiếu đến một lớp trừu tượng

Khi một hàm ảo được kế thừa, bản chất ảo của nó cũng được kế thừa

Điều này có nghiã là khi một lớp dẫn xuất kế thừa hàm ảo từ lớp cơ sở, một lớp

dẫn xuất thứ hai lại kế thừa lớp dẫn xuất thứ nhất, hàm ảo có thể được định nghiã

lại ở lớp dẫn xuất thứ hai (cũng như nó được định nghiã lại ở lớp dẫn xuất thứ nhất)

Ví dụ 3.1 Tạo một lớp trừu tượng

Trang 15

class triangle : public area {

Ví dụ 3.2 Minh hoạ việc bảo tồn bản chất ảo của hàm khi nó được kế thừa

// Virtual functions retain their virtual nature when inherited

#include <iostream.h>

class base {

public:

virtual void func() {

cout << "Using base version of func()\n";

}

};

Trang 16

class derived1 : public base {

// Derived2 inherits derived1

class derived2 : public derived1 {

Kết quả chương trình ?

Điều gì xảy ra khi cả hai lớp dẫn xuất đều không tái định hàm ảo func() ?

Trang 17

Bài tập III

1 Hãy tạo ra một đối tượng cho lớp area trong ví dụ 3.1 chương 9, điều gì sẽ xảy ra

?

2 Trong ví dụ 3.2 chương 9, thử xoá phần tái định hàm ảo func() của lớp derived2, rồi cho truy cập d_ob2 Kết qủa của chương trình thế nào ?

3 Tại sao không thể tạo ra một đối tượng thuộc lớp trừu tượng ?

IV/ Aùp dụng đa hình

Tại sao cần sử dụng đa hình ?

1/ Đa hình rất quan trọng vì nó đơn giản hoá các hệ thống phức tạp

• Đa hình là một quá trình áp dụng một giao diện cho hai hay nhiều trường hợp

tương tự nhau (nhưng khác biệt về mặt kỹ thuật), nó triển khai tư tưởng "một

giao diện cho nhiều phương thức"

Một giao diện hay và đơn giản được dùng để truy cập đến một số các hoạt động 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 :

Trang 18

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"

Trang 19

// Demonstrate virtual functons

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 {

Trang 20

if(tail) tail->next = item;

// Create a stack type list

class stack : public list {

Trang 21

cout << "Allocation error.\n";

exit(1);

}

item->num = i;

// put on front of list for stack-like operation

if(head) item->next = head;

Trang 22

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

Trang 23

char ch;

int i;

for(i=0; i<10; i++) {

cout << "Stack or Queue? (S/Q): ";

• 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

Trang 24

một khung cửa sổ chứa nội dung " Hello, Windows 98 ! "

#include <windows.h>

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,

PSTR szCmdLine, int iCmdShow)

wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;

wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;

wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ; wndclass.lpszMenuName = NULL ;

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

Trang 25

CW_USEDEFAULT, // initial y size

NULL, // parent window handle

NULL, // window menu handle

hInstance, // program instance handle

NULL) ; // creation parameters

////LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM

wParam, LPARAM lParam)

Trang 26

DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;

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

Trang 27

1 Xét đoạn chương trình sau đây Tìm lỗi và giải thích tại sao ?

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 ?

Ngày đăng: 21/08/2012, 15:34

Xem thêm

TỪ KHÓA LIÊN QUAN

w