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

hoa cuong có thì sử dụng – thích thì lao vào

38 6 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

Nội dung

 Ñeå baûo ñaûm xuaát lieäu töông öùng vôùi ñoái töôïng, phaûi coù caùch nhaän dieän ñoái töôïng, ta theâm moät vuøng döõ lieäu vaøo lôùp cô sôû ñeå nhaän dieän, vuøng naøy coù giaù tr[r]

(1)

Chương 5

Phương thức ảo tính đa hình

5.1 Bài tốn quản lý danh sách đo

ái tượng khác kiểu

5.2 Vùng chọn kiểu

5.3 Phương thức ảo

(2)

5.1 Bài toán quản lý danh sách đối tượng

khác kiểu

- Giả sử ta cần quản lý danh sách đối tượng có kiểu có thể khác nhau, ta cần giải hai vấn đề: Cách lưu trữ

thao tác xử lý.

- Xét trường hợp cụ thể, đối tượng người, sinh viên cơng nhân

- Về lưu trữ: Ta dùng union, trường hợp đối tượng phải có kích thước chứa đối tượng có kích thước lớn Điều gây lãng phí khơng gian lưu trữ Một cách thay lưu trữ đối tượng kích thước dùng danh sách (mảng, dslk, ) trỏ để quản lý đối tượng

(3)

5.2 Dùng vùng chọn kieåu

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

(4)

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

class Nguoi {

protected:

char *HoTen; int NamSinh; public:

Nguoi(char *ht, int ns):NamSinh(ns) {HoTen = strdup(ht);}

~Nguoi() {delete [] HoTen;}

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

void Ngu() const { cout << HoTen << " ngu tieng";}

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

(5)

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

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;}

};

class NuSinh : public SinhVien {

public:

NuSinh(char *ht, char *ms, int ns) : SinhVien(ht,ms,ns) {}

(6)

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

class CongNhan : public Nguoi {

protected:

double MucLuong; public:

CongNhan(char *n, double ml, int ns) : Nguoi(n,ns), MucLuong(ml) { }

void Xuat() const { cout << "Cong nhan, ten " << HoTen << " muc luong: " << MucLuong;}

};

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

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

(7)

Dùng vùng chọn kieåu

const int N = 4; void main()

{

Nguoi *a[N];

a[0] = new SinhVien("Vien Van Sinh", ”200001234", 1982);

a[1] = new NuSinh("Le Thi Ha Dong", ”200001235", 1984);

a[2] = new CongNhan("Tran Nhan Cong", 1000000, 1984);

a[3] = new Nguoi("Nguyen Thanh Nhan", 1960); XuatDs(4,a);

(8)

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

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

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

 Tất đối tượng quan điểm người thao tác thực thông qua trỏ đến lớp Người

 Để 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 vùng liệu vào lớp sở để nhận diện, vùng có giá trị phụ thuộc vào loại đối tượng gọi vùng chọn kiểu

(9)

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

class Nguoi

{

public:

enum LOAI {NGUOI, SV, CN}; protected:

char *HoTen; int NamSinh; public:

LOAI pl;

Nguoi(char *ht, int ns):NamSinh(ns), pl(NGUOI) {HoTen = strdup(ht);}

~Nguoi() {delete [] HoTen;}

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

void Ngu() const { cout << HoTen << " ngu tieng";}

(10)

Duøng vuøng chọn kiểu

class SinhVien : public Nguoi

{

protected:

char *MaSo; public:

SinhVien(char *n, char *ms, int ns) : Nguoi(n,ns) { MaSo = strdup(ms); pl = SV;}

~SinhVien() {delete [] MaSo;}

void Xuat() const { cout << "Sinh vien " << HoTen << ", ma so " << MaSo;}

};

class NuSinh : public SinhVien {

public:

NuSinh(char *ht, char *ms, int ns) : SinhVien(ht,ms,ns) {}

(11)

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

class CongNhan : public Nguoi {

protected:

double MucLuong; public:

CongNhan(char *n, double ml, int ns) : Nguoi(n,ns), MucLuong(ml) { pl = CN;}

void Xuat() const { cout << "Cong nhan, ten " << HoTen << " muc luong: " << MucLuong;}

};

(12)

Dùng vùng chọn kieåu

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

{

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

switch(an[i]->pl) {

case Nguoi::SV:

((SinhVien *)an[i])->Xuat(); break;

case Nguoi::CN:

((CongNhan *)an[i])->Xuat(); break;

default:

an[i]->Xuat(); break;

}

(13)

Dùng vùng chọn kieåu

const int N = 4;

void main() {

Nguoi *a[N];

a[0] = new SinhVien("Vien Van Sinh", "200001234", 1982);

a[1] = new NuSinh("Le Thi Ha Dong", "200001235", 1984);

a[2] = new CongNhan("Tran Nhan Cong", 1000000, 1984);

a[3] = new Nguoi("Nguyen Thanh Nhan", 1960); XuatDs(4,a);

}

 Xuất liệu đoạn chương trình là:

Sinh vien Vien Van Sinh, ma so 200001234 Sinh vien Le Thi Ha Dong, ma so 200001235

(14)(15)

Duøng vuøng chọn kiểu

 Cách tiếp cận giải vấn để: Lưu trữ đối tượng khác kiểu thao tác khác tương ứng với đối tượng Tuy nhiên có nhược điểm sau:

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

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

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

(16)

5.3 Phương thức ảo

 Con trỏ thuộc lớp sở trỏ đến lớp con:

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

 Ta mong muốn thông qua trỏ thuộc lớp sở truy xuất hàm thành phần đị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

 Phương thức ảo cho phép giải vấn đề Ta qui định hàm thành phần phương thức ảo cách thêm từ khoá virtual vào trước khai báo hàm

(17)

Phương thức ảo

class Nguoi {

protected:

char *HoTen; int NamSinh; public:

Nguoi(char *ht, int ns):NamSinh(ns) {HoTen = strdup(ht);}

~Nguoi() {delete [] HoTen;}

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

void Ngu() const { cout << HoTen << " ngu tieng";}

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

(18)

Phương thức ảo

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;}

};

class NuSinh : public SinhVien {

public:

NuSinh(char *ht, char *ms, int ns) : SinhVien(ht,ms,ns) {}

(19)

Phương thức ảo

class CongNhan : public Nguoi

{

protected:

double MucLuong; public:

CongNhan(char *n, double ml, int ns) : Nguoi(n,ns), MucLuong(ml) { }

void Xuat() const { cout << "Cong nhan, ten " << HoTen << " muc luong: " << MucLuong;}

};

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

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

(20)

Phương thức ảo

const int N = 4; void main()

{

Nguoi *a[N];

a[0] = new SinhVien("Vien Van Sinh", "200001234", 1982);

a[1] = new NuSinh("Le Thi Ha Dong", "200001235", 1984);

a[2] = new CongNhan("Tran Nhan Cong", 1000000, 1984);

a[3] = new Nguoi("Nguyen Thanh Nhan", 1960); XuatDs(4,a);

}

(21)

Phương thức ảo

Nguoi *pn;

pn = new SinhVien("Vien Van Sinh", "200001234", 1982);

pn->Xuat(); // Goi thao tac xuat cua lop Sinh vien

 Con trỏ pn thuộc lớp Nguoi trỏ đến đối tượng sinh viên, pn->Xuat() thực thao tác xuất lớp sinh viên

 Trở lại ví dụ trên, i a[i] trỏ đến đối tượng

thuộc loại khác nhau, thao tác tương ứng với lớp gọi

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

(22)

Thêm lớp mới

 Dùng phương thức ảo, ta dễ dàng nâng cấp sửa chữa Việc thêm loại đối tượng đơ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 xây dựng lớp kế thừa từ lớp sở lớp có định nghĩa lại phương thức (ảo) lớp tạo cần

class CaSi : public Nguoi {

protected:

double CatXe; public:

CaSi(char *ht, double cx, int ns) : Nguoi(ht,ns), CatXe(cx) {}

void Xuat() const { cout << "Ca si, " << HoTen << " co cat xe " << CatXe;}

(23)

Thêm lớp mới

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

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

an[i]->Xuat(); cout << "\n"; }

}

 Hàm XuatDs khơng thay đổi, hoạt động cho loại đối tượng ca sĩ thuộc lớp đời

(24)

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

 Phương thức ảo hoạt động thông qua trỏ

 Muốn hàm trở thành phương thức ảo có hai cách: Khai báo với từ khố virtual hàm tương ứng lớp sở phương thức ảo

 Phương thức ảo hoạt động hàm lớp sở lớp có nghi thức giao tiếp giống hệt

(25)

Ví dụ thêm phương thức ảo

(26)

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

 Khi gọi thao tác, khả chọn phiên tuỳ theo đối tượng để thực thông qua trỏ đến lớp sở gọi tính đa hình (polymorphisms)

 Cơ chế đa hình thực nhờ đối tượng có thêm bảng phương thức ảo Bảng chứa địa

phương thức ảo trình biên dịch khởi tạo cách ngầm định thiết lập đối tượng

 Khi thao tác thực thơng qua trỏ, hàm có địa bảng phương thức ảo gọi

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

(27)

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

 Trong ví dụ 2, đối tượng thuộc lớp Mamal, Dog,

(28)(29)

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

 Trong ví dụ quản lý danh sách đối tượng thuộc lớp Nguoi, SinhVien, CongNhan, … Thao tác dọn dẹp đối tượng cần thiết

const int N = 4; void main()

{

Nguoi *a[N];

a[0] = new SinhVien("Vien Van Sinh", "20001234", 1982);

a[1] = new NuSinh("Le Thi Ha Dong", "20001235", 1984);

a[2] = new CongNhan("Tran Nan Cong", 1000000, 1984);

a[3] = new Nguoi("Nguyen Thanh Nhan", 1960); XuatDs(4,a);

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

(30)

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

 Thông qua trỏ thuộc lớp sở Nguoi, có phương thức huỷ bỏ lớp Nguoi gọi

 Để bảo đảm việc dọn dẹp đầy đủ, ta dùng phương thức huỷ bỏ ảo

class Nguoi {

protected:

char *HoTen; int NamSinh; public:

Nguoi(char *ht, int ns):NamSinh(ns) {HoTen = strdup(ht);}

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

virtual void Xuat(ostream &os) const { os <<

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

(31)

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

 C++ không cung cấp chế thiết lập đối tượng có khả đa hình theo chế hàm thành phần ảo

 Tuy nhiên ta “thu xếp” để tạo đối tượng theo nghĩa “ảo” Xem ví dụ pttl_ao.cpp

(32)

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

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

typedef CGBmp * CGBmpPtr; class CGBmp

{

protected: // public:

virtual ~CGBmp(){Release();} virtual void Release() = 0;

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

(33)

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

class CBmp : public CGBmp

{

// public:

CBmp(const String &pathName); void Release();

void Draw() const; //

};

class CGif: public CGBmp {

//

public:

CGif(const String &pathName); void Release();

(34)

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

class CJpg: public CGBmp

{

//

public:

CJpg(const String &pathName); void Release();

void Draw() const; //

};

FILETYPE GetFileType(const String &pathName) {

String FileExt = GetFileExt(pathName);

if (FileExt == ".DIB" || FileExt == ".BMP") return BMP;

else if (FileExt == ".JPG") return JPG;

else if (FileExt == ".GIF") return GIF;

(35)

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

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

switch (GetFileType(pathName)) {

case BMP:

return new CBmp(pathName); case GIF:

return new CGif(pathName); case JPG:

return new CJpg(pathName); default:

return NULL; }

}

void main() {

(36)

5.5 Phương thức ảo tuý lớp sở trừu tượng

 Lớp sở trừu tượng lớp sở khơng có đối tượng thuộc Một đối tượng thuộc lớp sở trừu tượng phải thuộc lớp

 Xét lớp Circle, Rectangle, Square kế thừa từ lớp Shape, xem chương trình nguồn pta_tt.cpp

 Trong ví dụ trên, hàm lớp Shape có nội dung

nhưng nội dung khơng có ý nghĩa Đồng thời ta ln ln tạo đối tượng thuộc lớp Shape, điều không

đúng với tư tưởng phương pháp luận hướng đối tượng  Ta thay cho nội dung khơng có ý nghĩa

(37)

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

 Khi lớp có phương thức ảo tuý, lớp trở thành lớp sở trừu tượng Ta tạo đối tượng thuộc lớp sở tuý

 Ta định nghĩa phương thức ảo tuý, có đối tượng thuộc lớp gọi Xem pta_tt2

 Trong ví dụ trên, hàm thành phần lớp Shape phương thức ảo tuý Nó bảo đảm tạo đối tượng thuộc lớp Shape Ví dụ định nghĩa nội dung cho phương thức ảo tuý, có đối tượng thuộc lớp gọi

(38)

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

Ngày đăng: 20/04/2021, 01:50

w