1. Trang chủ
  2. » Giáo án - Bài giảng

tài liệu bài giảng đa hình

49 261 0

Đ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 49
Dung lượng 287 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

} Phương thức ảo xuat được khai báo ở lớp Nguoi cho phép sử dụng con trỏ đến lớp cơ sở Nguoi nhưng trỏ đến một đối tượng thuộc lớp con Sinh viên, công nhân gọi đúng thao tác ở lớp con:

Trang 1

Đa hình

Trang 2

Bài toán quản lý một danh sách các đối tượng khác kiểu

• Giả sử ta cần quản lý một danh sách các đối

tượng có kiểu có thể khác nhau, ta cần giải

quyết hai vấn đề: Cách lưu trữ và thao tác xử lý.

• Xét trường hợp cụ thể, các đối tượng có thể là

người, sinh viên hoặc công nhân.

Trang 3

Bài toán quản lý một danh sách các đối tượng khác kiểu

• Về lưu trữ: Ta có thể dùng union, trong trường hợp này mỗi đối tượng phải có kích thước chứa được đối tượng có kích thước lớn nhất Điều này gây lãng phí không gian lưu trữ Một cách thay thế là lưu trữ đối tượng bằng đúng kích thước của nó và dùng một danh sách (mảng, dslk, ) các con trỏ để quản lý các đối tượng

• Về thao tác, phải thoả yêu cầu đa hình: Thao tác

có hoạt động khác nhau ứng với các loại đối tượng khác nhau Có hai cách giải quyết là vùng chọn kiểu và phương thức ảo.

Trang 4

Đa hình và Hướng đối tượng

• Định nghĩa: là hiện tượng các đối tượng thuộc

các lớp khác nhau có khả năng hiểu cùng một thông điệp theo các cách khác nhau

• Ví dụ: nhận được cùng một thông điệp “nhảy”, một con kangaroo và một con cóc nhảy theo

hai kiểu khác nhau: chúng cùng có hành vi

“nhảy” nhưng các hành vi này có nội dung

khác nhau

Trang 5

Dùng vùng chọn kiểu

• Về lưu trữ: Ta sẽ dùng một mảng các con trỏ đến lớp cơ sở để có thể trỏ đến các đối tượng thuộc lớp con

• Xét lớp Người và các lớp kế thừa sinh

viên và công nhân Thao tác ta quan tâm

là xuat Ta cần bảo đảm thao tác xuất áp

dụng cho lớp sinh viên và lớp công nhân khác nhau.

Trang 6

~Nguoi() {delete [] HoTen;}

void An() const

{ cout << HoTen << " an 3 chen com";} void Ngu() const

{ cout << HoTen << " ngu ngay 8 tieng";} void Xuat() const

{ cout << "Nguoi, ho ten: " << HoTen << " sinh " << NamSinh; }

};

Trang 7

class SinhVien : public Nguoi

{

protected:

char *MaSo;

public:

SinhVien(char *n, char *ms, int ns) :

Nguoi(n,ns) { MaSo = strdup(ms);}

~SinhVien() {delete [] MaSo;}

void Xuat() const

{ cout << "Sinh vien " << HoTen << ",

ma so " << MaSo;}

};

Dùng vùng chọn kiểu

Trang 8

class NuSinh : public SinhVien

Trang 9

class CongNhan : public Nguoi

{ cout << "Cong nhan, ten " << HoTen

<< " muc luong: " << MucLuong;} };

Trang 10

void XuatDs(int n, Nguoi *an[]) {

for (int i = 0; i < n; i++) {

Trang 12

Dùng vùng chọn kiểu

• Xuất liệu cho đoạn chương trình trên như sau:

• Tất cả mọi đối tượng đều được quan điểm như người vì thao tác được thực hiện thông qua con trỏ đến lớp Người.

Nguoi, ho ten: Vien Van Sinh sinh 1982

Nguoi, ho ten: Le Thi Ha Dong sinh 1984

Nguoi, ho ten: Tran Nhan Cong sinh 1984

Nguoi, ho ten: Nguyen Thanh Nhan sinh 1960

Trang 13

Dùng vùng chọn kiểu

• Để bảo đảm xuất liệu tương ứng với đối tượng, phải có cách nhận diện đối tượng, ta thêm một vùng dữ liệu vào lớp cơ sở để nhận diện, vùng này có giá trị phụ thuộc vào loại của đối tượng

và được gọi là vùng chọn kiểu.

• Các đối tượng thuộc lớp người có cùng giá trị cho vùng chọn kiểu, các đối tượng thuộc lớp

sinh viên có giá trị của vùng chọn kiểu khác của lớp người.

Trang 14

~Nguoi() {delete [] HoTen;}

void An() const

{ cout << HoTen << " an 3 chen com";}

void Ngu() const

{ cout << HoTen << " ngu ngay 8 tieng";}

void Xuat() const { cout << "Nguoi, ho ten: " << HoTen << " sinh " << NamSinh; }

};

Trang 15

~SinhVien() {delete [] MaSo;}

void Xuat() const

{ cout << "Sinh vien " << HoTen

<< ", ma so " << MaSo;}

};

Trang 16

class NuSinh : public SinhVien

Trang 17

void Xuat() const

{ cout << "Cong nhan, ten " << HoTen << " muc luong: " << MucLuong;} };

Trang 18

Dùng vùng chọn kiểu

void XuatDs(int n, Nguoi *an[]) {

for (int i = 0; i < n; i++) {

}

}

Khi thao tác ta phải căn cứ vào giá trị của vùng chọn kiểu để “ép kiểu” phù hợp.

Trang 19

Sinh vien Vien Van Sinh, ma so 200001234

Sinh vien Le Thi Ha Dong, ma so 200001235

Cong nhan, ten Tran Nhan Cong muc luong:1000000 Nguoi, ho ten: Nguyen Thanh Nhan sinh 1960

Trang 20

Dùng vùng chọn kiểu

• Cách tiếp cận trên giải quyết được vấn đề: lưu trữ

được các đối tượng khác kiểu nhau và thao tác khác nhau tương ứng với đối tượng

• Tuy nhiên nó có các nhược điểm sau:

– Dài dòng với nhiều switch, case.

– Dễ sai sót, khó sửa vì trình biên dịch bị cơ chế ép kiểu che mắt.

– Khó nâng cấp ví dụ thêm một loại đối tượng mới, đặc biệt khi chương trình lớn.

• Các nhược điểm trên có thể được khắc phục nhờ

phương thức ảo.

Trang 21

Phương thức ảo

• Con trỏ thuộc lớp cơ sở có thể trỏ đến lớp con:

Nguoi* pn = new SinhVien(“Le Vien Sinh”, 200001234, 1982);

• Ta mong muốn thông qua con trỏ thuộc lớp cơ

sở có thể truy xuất hàm thành phần được định nghĩa lại ở lớp con:

pn->Xuat(); // Mong muon: goi Xuat cua lop sinh

vien, // thuc te: goi Xuat cua lop Nguoi

Trang 22

Phương thức ảo

• Phương thức ảo cho phép giải quyết vấn

đề Ta qui định một hàm thành phần là

phương thức ảo bằng cách thêm từ khoá

virtual vào trước khai báo hàm.

• Trong ví dụ trên, ta thêm từ khoá virtual vào trước khai báo của hàm xuat.

Trang 23

~Nguoi() {delete [] HoTen;}

void An() const

{ cout << HoTen << " an 3 chen com";}

void Ngu() const

{ cout << HoTen << " ngu ngay 8 tieng";}

virtual void Xuat() const {

cout << "Nguoi, ho ten: " << HoTen

<< " sinh " << NamSinh;

}

};

Trang 24

~SinhVien() {delete [] MaSo;}

void Xuat() const {

cout << "Sinh vien " << HoTen

<< ", ma so " << MaSo;

}

};

Trang 25

class NuSinh : public SinhVien

Trang 26

cout << "Cong nhan, ten "

<< HoTen << " muc luong: " << MucLuong; }

};

Trang 27

void XuatDs(int n, Nguoi *an[]) {

for (int i = 0; i < n; i++)

Trang 28

}

Phương thức ảo xuat được khai báo ở lớp Nguoi cho phép

sử dụng con trỏ đến lớp cơ sở (Nguoi) nhưng trỏ đến một đối tượng thuộc lớp con (Sinh viên, công nhân) gọi đúng thao tác

ở lớp con:

Trang 29

Phương thức ảo

• Con trỏ pn thuộc lớp Nguoi nhưng trỏ đến đối tượng

sinh viên, vì vậy pn->Xuat() thực hiện thao tác xuất của lớp sinh viên

• Trở lại ví dụ trên, khi i a[i] lần lượt trỏ đến các đối tượng thuộc các loại khác nhau, thao tác tương ứng với lớp sẽ được gọi

• Dùng phương thức ảo khắc phục được các nhược điểm của cách tiếp cận dùng vùng chọn kiểu:

• Thao tác đơn giản không phải dùng switch/case vì vậy

khó sai, dễ sửa

Nguoi *pn;

pn = new SinhVien("Vien Van Sinh“,"200001234“,1982); pn->Xuat(); // Goi thao tac xuat cua lop Sinh vien

Trang 30

Thêm lớp con mới

class CaSi : public Nguoi

Dùng phương thức ảo, ta dễ dàng nâng cấp sửa chữa

Việc thêm một loại đối tượng mới rất đơn giản, ta không cần phải sửa đổi thao tác xử lý (hàm XuatDs) Qui trình thêm chỉ là xây dựng lớp con kế thừa từ lớp cơ sở hoặc các lớp con đã có và định nghĩa lại phương thức (ảo) ở lớp mới tạo nếu cần

Trang 31

Thêm lớp con mới

void XuatDs(int n, Nguoi *an[])

Trang 32

Các lưu ý khi sử dụng phương thức ảo

• Phương thức ảo chỉ hoạt động thông qua con trỏ.

• Muốn một hàm trở thành phương thức ảo có hai cách: Khai báo với từ khoá virtual hoặc hàm tương ứng ở lớp cơ sở đã là phương thức ảo.

• Phương thức ảo chỉ hoạt động nếu các hàm ở lớp

cơ sở và lớp con có nghi thức giao tiếp giống hệt nhau.

• Nếu ở lớp con định nghĩa lại phương thức ảo thì

sẽ gọi phương thức ở lớp cơ sở (gần nhất có định nghĩa).

Trang 33

Cơ chế thực hiện phương thức ảo

• Khi gọi một thao tác, khả năng chọn đúng phiên bản tuỳ theo đối tượng để thực hiện thông qua con trỏ đến lớp cơ sở được gọi là tính đa hình (polymorphisms).

• Cơ chế đa hình được thực hiện nhờ ở mỗi đối tượng có thêm một bảng phương thức ảo Bảng này chứa địa chỉ của các phương thức ảo và nó được trình biên dịch khởi tạo một cách ngầm

định khi thiết lập đối tượng.

Trang 34

Cơ chế thực hiện phương thức ảo

• Khi thao tác được thực hiện thông qua con trỏ, hàm có địa chỉ trong bảng phương thức ảo sẽ được gọi.

• Trong ví dụ trên, mỗi đối tượng thuộc lớp cơ sở Người có bảng phương thức ảo có một phần tử

là địa chỉ hàm Nguoi::Xuat Mỗi đối tượng thuộc lớp SinhVien có bảng tương tự nhưng nội dung

là địa chỉ của hàm SinhVien::Xuat.

Trang 35

Cơ chế thực hiện phương thức ảo

• Trong ví dụ 2, mỗi đối tượng thuộc các lớp Mamal, Dog, Cat, Horse, Pig đều có bảng phương thức ảo với hai phần tử, địa chỉ

của hàm Speak và của hàm Move.

Trang 37

Phương thức huỷ bỏ ảo

Trang 38

Phương thức huỷ bỏ ảo

• Thông qua con trỏ thuộc lớp cơ sở Nguoi, chỉ có phương thức huỷ bỏ của lớp Nguoi được gọi.

• Để bảo đảm việc dọn dẹp là đầy đủ, ta

dùng phương thức huỷ bỏ ảo.

Trang 39

virtual ~Nguoi() {delete [] HoTen;}

virtual void Xuat(ostream &os) const { os

<< "Nguoi, ho ten: " << HoTen << " sinh "

<< NamSinh; }

void Xuat() const { Xuat(cout); }

};

Trang 40

Phương thức thiết lập ảo

• C++ không cung cấp cơ chế thiết lập đối tượng có khả năng đa hình theo cơ chế

Trang 41

Phương thức thiết lập ảo

enum FILETYPE {UNKNOWN, BMP, GIF, JPG};

virtual void Release() = 0;

static CGBmpPtr NewBmp(const String &pathName); virtual void Draw() const;

};

Trang 42

Phương thức thiết lập ảo

Trang 43

class CGif: public CGBmp

Trang 44

Phương thức thiết lập ảo

Trang 45

FILETYPE GetFileType(const String &pathName) {

String FileExt = GetFileExt(pathName);

if (FileExt == ".DIB" || FileExt ==

Trang 46

Phương thức thiết lập ảo

CGBmpPtr CGBmp::NewBmp(const String &pathName) {

Trang 47

Phương thức thuần ảo và lớp cơ sở trừu

tượng

• Lớp cơ sở trừu tượng là lớp cơ sở không có đối

tượng nào thuộc chính nó Một đối tượng thuộc lớp

cơ sở trừu tượng phải thuộc một trong các lớp con.

• Xét các lớp Circle, Rectangle, Square kế thừa từ lớp Shape

• Trong ví dụ trên, các hàm trong lớp Shape có nội dung nhưng nội dung không có ý nghĩa Đồng thời

ta luôn luôn có thể tạo được đối tượng thuộc lớp Shape, điều này không đúng với tư tưởng của

phương pháp luận hướng đối tượng

Trang 48

Phương thức ảo thuần tuý và lớp cơ sở trừu tượng

• Ta có thể thay thế cho nội dung không có ý

nghĩa bằng phương thức ảo thuần tuý Phương thức ảo thuần tuý là phương thức ảo không có nội dung.

• Khi lớp có phương thức ảo thuần tuý, lớp trở

thành lớp cơ sở trừu tượng Ta không thể tạo

đối tượng thuộc lớp cơ sở thuần tuý.

• Ta có thể định nghĩa phương thức ảo thuần tuý, nhưng chỉ có các đối tượng thuộc lớp con có thể gọi nó

Trang 49

• Trong ví dụ trên, các hàm thành phần trong lớp

Shape là phương thức ảo thuần tuý Nó bảo đảm không thể tạo được đối tượng thuộc lớp Shape Ví

dụ trên cũng định nghĩa nội dung cho phương thức

ảo thuần tuý, nhưng chỉ có các đối tượng thuộc lớp con có thể gọi.

• Phương thức ảo thuần tuý có ý nghĩa cho việc tổ

chức sơ đồ phân cấp các lớp, nó đóng vai trò chừa sẵn chỗ trống cho các lớp con điền vào với phiên bản phù hợp.

• Bản thân các lớp con của lớp cơ sở trừu tượng

cũng có thể là lớp cơ sở trừu tượng

Phương thức ảo thuần tuý và lớp cơ sở trừu tượng

Ngày đăng: 17/04/2015, 09:54

TỪ KHÓA LIÊN QUAN

w