380 likes | 515 Views
Chöông 5 Phöông thöùc aûo vaø tính ña hình. 5.1 Baøi toaùn quaûn lyù moät danh saùch caùc ñoái töôïng khaùc kieåu 5.2 Vuøng choïn kieåu 5.3 Phöông thöùc aûo 5.4 Phöông thöùc thieát laäp aûo 5.5 Phöông thöùc aûo thuaàn tuyù.
E N D
Chöông 5Phöông thöùc aûo vaø tính ña hình 5.1 Baøi toaùn quaûn lyù moät danh saùch caùc ñoái töôïng khaùc kieåu 5.2 Vuøng choïn kieåu 5.3 Phöông thöùc aûo 5.4 Phöông thöùc thieát laäp aûo 5.5 Phöông thöùc aûo thuaàn tuyù
5.1 Baøi toaùn quaûn lyù moät danh saùch caùc ñoái töôïng khaùc kieåu • Giaû söû ta caàn quaûn lyù moät danh saùch caùc ñoái töôïng coù kieåu coù theå khaùc nhau, ta caàn giaûi quyeát hai vaán ñeà: Caùch löu tröõ vaø thao taùc xöû lyù. • Xeùt tröôøng hôïp cuï theå, caùc ñoái töôïng coù theå laø ngöôøi, sinh vieân hoaëc coâng nhaân. • Veà löu tröõ: Ta coù theå duøng union, trong tröôøng hôïp naøy moãi ñoái töôïng phaûi coù kích thöôùc chöùa ñöôïc ñoái töôïng coù kích thöôùc lôùn nhaát. Ñieàu naøy gaây laõng phí khoâng gian löu tröõ. Moät caùch thay theá laø löu tröõ ñoái töôïng baèng ñuùng kích thöôùc cuûa noù vaø duøng moät danh saùch (maûng, dslk,...) caùc con troû ñeå quaûn lyù caùc ñoái töôïng. • Veà thao taùc, phaûi thoaû yeâu caàu ña hình: Thao taùc coù hoaït ñoäng khaùc nhau öùng vôùi caùc loaïi ñoái töôïng khaùc nhau. Coù hai caùch giaûi quyeát laø vuøng choïn kieåu vaø phöông thöùc aûo.
5.2 Duøng vuøng choïn kieåu • Veà löu tröõ: Ta seõ duøng moät maûng caùc con troû ñeán lôùp cô sôû ñeå coù theå troû ñeán caùc ñoái töôïng thuoäc lôùp con. • Xeùt lôùp Ngöôøi vaø caùc lôùp keá thöøa sinh vieân vaø coâng nhaân. Thao taùc ta quan taâm laø xuat. Ta caàn baûo ñaûm thao taùc xuaát aùp duïng cho lôùp sinh vieân vaø lôùp coâng nhaân khaùc nhau.
Duøng vuøng choïn kieå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 3 chen com";} • void Ngu() const { cout << HoTen << " ngu ngay 8 tieng";} • void Xuat() const { cout << "Nguoi, ho ten: " << HoTen << " sinh " << NamSinh; } • };
Duøng vuøng choïn kieå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) {} • void An() const { cout << HoTen << " ma so " << MaSo << " an 2 to pho";} • };
Duøng vuøng choïn kieå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++) • { • an[i]->Xuat(); • cout << "\n"; • } • }
Duøng vuøng choï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); • }
Duøng vuøng choïn kieåu • Xuaát lieäu cho ñoaïn chöông trình treân 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 • Taát caû moïi ñoái töôïng ñeàu ñöôïc quan ñieåm nhö ngöôøi vì thao taùc ñöôïc thöïc hieän thoâng qua con troû ñeán lôùp Ngöôøi. • Ñ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ò phuï thuoäc vaøo loaïi cuûa ñoái töôïng vaø ñöôïc goïi laø vuøng choïn kieåu. • Caùc ñoái töôïng thuoäc lôùp ngöôøi coù cuøng giaù trò cho vuøng choïn kieåu, caùc ñoái töôïng thuoäc lôùp sinh vieân coù giaù trò cuûa vuøng choïn kieåu khaùc cuûa lôùp ngöôøi.
Duøng vuøng choïn kieå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 3 chen com";} • void Ngu() const { cout << HoTen << " ngu ngay 8 tieng";} • void Xuat() const { cout << "Nguoi, ho ten: " << HoTen << " sinh " << NamSinh; } • };
Duøng vuøng choïn kieå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) {} • void An() const { cout << HoTen << " ma so " << MaSo << " an 2 to pho";} • };
Duøng vuøng choïn kieå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;} • }; • Khi thao taùc ta phaûi caên cöù vaøo giaù trò cuûa vuøng choïn kieåu ñeå “eùp kieåu” phuø hôïp.
Duøng vuøng choï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; • } • cout << "\n"; • } • }
Duøng vuøng choï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); • } • Xuaát lieäu cuûa ñoaïn chöông trình treân seõ laø: • 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
Duøng vuøng choïn kieåu • Caùch tieáp caän treân giaûi quyeát ñöôïc vaán ñeå: Löu tröõ ñöôïc caùc ñoái töôïng khaùc kieåu nhau vaø thao taùc khaùc nhau töông öùng vôùi ñoái töôïng. Tuy nhieân noù coù caùc nhöôïc ñieåm sau: • Daøi doøng vôùi nhieàu switch, case. • Deã sai soùt, khoù söûa vì trình bieân dòch bò cô cheá eùp kieåu che maét. • Khoù naâng caáp ví duï theâm moät loaïi ñoái töôïng môùi, ñaëc bieät khi chöông trình lôùn. • Caùc nhöôïc ñieåm treân coù theå ñöôïc khaéc phuïc nhôø phöông thöùc aûo.
5.3 Phöông thöùc aûo • Con troû thuoäc lôùp cô sôû coù theå troû ñeán lôùp con: • Nguoi* pn = new SinhVien(“Le Vien Sinh”, 200001234, 1982); • Ta mong muoán thoâng qua con troû thuoäc lôùp cô sôû coù theå truy xuaát haøm thaønh phaàn ñöôïc ñònh nghóa laï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 aûo cho pheùp giaûi quyeát vaán ñeà. Ta qui ñònh moät haøm thaønh phaàn laø phöông thöùc aûo baèng caùch theâm töø khoaù virtual vaøo tröôùc khai baùo haøm. • Trong ví duï treân, ta theâm töø khoaù virtual vaøo tröôùc khai baùo cuûa haøm xuat.
Phöông thöùc aû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 3 chen com";} • void Ngu() const { cout << HoTen << " ngu ngay 8 tieng";} • virtual void Xuat() const { cout << "Nguoi, ho ten: " << HoTen << " sinh " << NamSinh; } • };
Phöông thöùc aû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) {} • void An() const { cout << HoTen << " ma so " << MaSo << " an 2 to pho";} • };
Phöông thöùc aû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++) • { • an[i]->Xuat(); • cout << "\n"; • } • }
Phöông thöùc aû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); • } • Phöông thöùc aûo xuat ñöôïc khai baùo ôû lôùp Nguoi cho pheùp söû duïng con troû ñeán lôùp cô sôû (Nguoi) nhöng troû ñeán moät ñoái töôïng thuoäc lôùp con (Sinh vieân, coâng nhaân) goïi ñuùng thao taùc ôû lôùp con:
Phöông thöùc aûo • Nguoi *pn; • pn = new SinhVien("Vien Van Sinh", "200001234", 1982); • pn->Xuat(); // Goi thao tac xuat cua lop Sinh vien • Con troû pn thuoäc lôùp Nguoi nhöng troû ñeán ñoái töôïng sinh vieân, vì vaäy pn->Xuat() thöïc hieän thao taùc xuaát cuûa lôùp sinh vieân. • Trôû laïi ví duï treân, khi i a[i] laàn löôït troû ñeán caùc ñoái töôïng thuoäc caùc loaïi khaùc nhau, thao taùc töông öùng vôùi lôùp seõ ñöôïc goïi. • Duøng phöông thöùc aûo khaéc phuïc ñöôïc caùc nhöôïc ñieåm cuûa caùch tieáp caän duøng vuøng choïn kieåu: • Thao taùc ñôn giaûn khoâng phaûi duøng switch/case vì vaäy khoù sai, deã söûa.
Theâm lôùp con môùi • Duøng phöông thöùc aûo, ta deã daøng naâng caáp söûa chöõa. Vieäc theâm moät loaïi ñoái töôïng môùi raát ñôn giaûn, ta khoâng caàn phaûi söûa ñoåi thao taùc xöû lyù (haøm XuatDs). Qui trình theâm chæ laø xaây döïng lôùp con keá thöøa töø lôùp cô sôû hoaëc caùc lôùp con ñaõ coù vaø ñònh nghóa laïi phöông thöùc (aûo) ôû lôùp môùi taïo neáu caà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;} • };
Theâm lôùp con môùi • void XuatDs(int n, Nguoi *an[]) • { • for (int i = 0; i < n; i++) • { • an[i]->Xuat(); • cout << "\n"; • } • } • Haøm XuatDs khoâng thay ñoåi, nhöng noù coù theå hoaït ñoäng cho caùc loaïi ñoái töôïng ca só thuoäc lôùp môùi ra ñôøi. • Coù theå xem nhö thao taùc XuatDs ñöôïc vieát tröôùc cho caùc lôùp con chaùu chöa ra ñôøi.
Caùc löu yù khi söû duïng phöông thöùc aûo • Phöông thöùc aûo chæ hoaït ñoäng thoâng qua con troû. • Muoán moät haøm trôû thaønh phöông thöùc aûo coù hai caùch: Khai baùo vôùi töø khoaù virtual hoaëc haøm töông öùng ôû lôùp cô sôû ñaõ laø phöông thöùc aûo. • Phöông thöùc aûo chæ hoaït ñoäng neáu caùc haøm ôû lôùp cô sôû vaø lôùp con coù nghi thöùc giao tieáp gioáng heät nhau. • Neáu ôû lôùp con ñònh nghóa laïi phöông thöùc aûo thì seõ goïi phöông thöùc ôû lôùp cô sôû (gaàn nhaát coù ñònh nghóa).
Ví duï theâm veà phöông thöùc aûo • Moät ví duï töông töï veà söû duïng phöông thöùc aûo laø quaûn lyù moät danh saùch caùc ñoäng vaät. Xem mamal.cpp
Cô cheá thöïc hieän phöông thöùc aûo • Khi goïi moät thao taùc, khaû naêng choïn ñuùng phieân baûn tuyø theo ñoái töôïng ñeå thöïc hieän thoâng qua con troû ñeán lôùp cô sôû ñöôïc goïi laø tính ña hình (polymorphisms). • Cô cheá ña hình ñöôïc thöïc hieän nhôø ôû moãi ñoái töôïng coù theâm moät baûng phöông thöùc aûo. Baûng naøy chöùa ñòa chæ cuûa caùc phöông thöùc aûo vaø noù ñöôïc trình bieân dòch khôûi taïo moät caùch ngaàm ñònh khi thieát laäp ñoái töôïng. • Khi thao taùc ñöôïc thöïc hieän thoâng qua con troû, haøm coù ñòa chæ trong baûng phöông thöùc aûo seõ ñöôïc goïi. • Trong ví duï treân, moãi ñoái töôïng thuoäc lôùp cô sôû Ngöôøi coù baûng phöông thöùc aûo coù moät phaàn töû laø ñòa chæ haøm Nguoi::Xuat. Moãi ñoái töôïng thuoäc lôùp SinhVien coù baûng töông töï nhöng noäi dung laø ñòa chæ cuûa haøm SinhVien::Xuat.
Cô cheá thöïc hieän phöông thöùc aûo • Trong ví duï 2, moãi ñoái töôïng thuoäc caùc lôùp Mamal, Dog, Cat, Horse, Pig ñeàu coù baûng phöông thöùc aûo vôùi hai phaàn töû, ñòa chæ cuûa haøm Speak vaø cuûa haøm Move.
Phöông thöùc huyû boû aûo • Trong ví duï quaûn lyù danh saùch caùc ñoái töôïng thuoäc caùc lôùp Nguoi, SinhVien, CongNhan, … Thao taùc doïn deïp ñoái töôïng laø caàn thieá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++) • delete a[i]; • }
Phöông thöùc huyû boû aûo • Thoâng qua con troû thuoäc lôùp cô sôû Nguoi, chæ coù phöông thöùc huyû boû cuûa lôùp Nguoi ñöôïc goïi. • Ñeå baûo ñaûm vieäc doïn deïp laø ñaày ñuû, ta duøng phöông thöùc huyû boû aû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; } • void Xuat() const { Xuat(cout); } • };
5.4 Phöông thöùc thieát laäp aûo • C++ khoâng cung caáp cô cheá thieát laäp ñoái töôïng coù khaû naêng ña hình theo cô cheá haøm thaønh phaàn aûo. • Tuy nhieân ta coù theå “thu xeáp” ñeå coù theå taïo ñoái töôïng theo nghóa “aûo”. Xem ví duï pttl_ao.cpp • Phöông thöùc thieát laäp aûo cuõng coù theå ñöôïc hieän thöïc baèng caùch duøng haøm thaønh phaàn tónh ñeå taïo ñoái töôïng.
Phöông thöùc thieát laäp aû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; • };
Phöông thöùc thieát laäp aû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(); • void Draw() const; • //... • };
Phöông thöùc thieát laäp aû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; • else return UNKNOWN; • }
Phöông thöùc thieát laäp aû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() • { • CGBmpPtr p = CGBmp::NewBmp("Lena.jpg"); • p->Draw(); • }
5.5 Phöông thöùc aûo thuaàn tuyù vaø lôùp cô sôû tröøu töôïng • Lôùp cô sôû tröøu töôïng laø lôùp cô sôû khoâng coù ñoái töôïng naøo thuoäc chính noù. Moät ñoái töôïng thuoäc lôùp cô sôû tröøu töôïng phaûi thuoäc moät trong caùc lôùp con. • Xeùt caùc lôùp Circle, Rectangle, Square keá thöøa töø lôùp Shape, xem chöông trình nguoàn pta_tt.cpp • Trong ví duï treân, caùc haøm trong lôùp Shape coù noäi dung nhöng noäi dung khoâng coù yù nghóa. Ñoàng thôøi ta luoân luoân coù theå taïo ñöôïc ñoái töôïng thuoäc lôùp Shape, ñieàu naøy khoâng ñuùng vôùi tö töôûng cuûa phöông phaùp luaän höôùng ñoái töôïng. • Ta coù theå thay theá cho noäi dung khoâng coù yù nghóa baèng phöông thöùc aûo thuaàn tuyù. Phöông thöùc aûo thuaàn tuyù laø phöông thöùc aûo khoâng coù noäi dung.
Phöông thöùc aûo thuaàn tuyù vaø lôùp cô sôû tröøu töôïng • Khi lôùp coù phöông thöùc aûo thuaàn tuyù, lôùp trôû thaønh lôùp cô sôû tröøu töôïng. Ta khoâng theå taïo ñoái töôïng thuoäc lôùp cô sôû thuaàn tuyù. • Ta coù theå ñònh nghóa phöông thöùc aûo thuaàn tuyù, nhöng chæ coù caùc ñoái töôïng thuoäc lôùp con coù theå goïi noù. Xem pta_tt2 • Trong ví duï treân, caùc haøm thaønh phaàn trong lôùp Shape laø phöông thöùc aûo thuaàn tuyù. Noù baûo ñaûm khoâng theå taïo ñöôïc ñoái töôïng thuoäc lôùp Shape. Ví duï treân cuõng ñònh nghóa noäi dung cho phöông thöùc aûo thuaàn tuyù, nhöng chæ coù caùc ñoái töôïng thuoäc lôùp con coù theå goïi. • Phöông thöùc aûo thuaàn tuyù coù yù nghóa cho vieäc toå chöùc sô ñoà phaân caáp caùc lôùp, noù ñoùng vai troø chöøa saün choã troáng cho caùc lôùp con ñieàn vaøo vôùi phieân baûn phuø hôïp.
Phöông thöùc aûo thuaàn tuyù vaø lôùp cô sôû tröøu töôïng • Baûn thaân caùc lôùp con cuûa lôùp cô sôû tröøu töôïng cuõng coù theå laø lôùp cô sôû tröøu töôïng, nhö ví duï pta_tt3.cpp.