在本文中,您將了解虛函數(shù)及其使用位置。此外,您還將學(xué)習(xí)純虛函數(shù)和抽象類。
虛函數(shù)是基類中的成員函數(shù),您希望在派生類中重新定義這些函數(shù)。
在詳細(xì)介紹之前,讓我們先了解一下為什么首先需要虛函數(shù)。
讓我們假設(shè),我們正在開發(fā)一個(gè)游戲(比如道具:武器)。
我們創(chuàng)建了Weapon該類并派生了兩個(gè)類,Bomb和Gun加載了各自武器的功能。
#include <iostream> using namespace std; class Weapon { public: void loadFeatures() { cout << "載入武器特性。\n"; } }; class Bomb : public Weapon { public: void loadFeatures() { cout << "裝載刀的特性。\n"; } }; class Gun : public Weapon { public: void loadFeatures() { cout << "裝載槍的特性\n"; } }; int main() { Weapon *w = new Weapon; Bomb *b = new Bomb; Gun *g = new Gun; w->loadFeatures(); b->loadFeatures(); g->loadFeatures(); return 0; }
輸出結(jié)果
裝載武器特性。 裝載刀的特性。 裝載槍的特性。
我們分別定義了Weapon,Bomb和Gun類的三個(gè)指針對(duì)象w,b和g。 并且,我們使用以下命令調(diào)用每個(gè)對(duì)象的loadFeatures()成員函數(shù):
w->loadFeatures(); b->loadFeatures(); g->loadFeatures();
完美的作品!
但是,我們的游戲項(xiàng)目開始變得越來(lái)越大。并且,我們決定創(chuàng)建一個(gè)單獨(dú)的Loader類來(lái)加載武器功能。
此類Loader根據(jù)選擇的武器加載武器的其他功能。
class Loader { public: void loadFeatures(Weapon *weapon) { weapon->features(); } };
loadFeatures()負(fù)載特定武器的特征。
#include <iostream> using namespace std; class Weapon { public: Weapon() { cout << "裝載武器特性。\n"; } void features() { cout << "裝載武器特性。\n"; } }; class Bomb : public Weapon { public: void features() { this->Weapon::features(); cout << "裝載刀的特性。\n"; } }; class Gun : public Weapon { public: void features() { this->Weapon::features(); cout << "加載槍的特性。\n"; } }; class Loader { public: void loadFeatures(Weapon *weapon) { weapon->features(); } }; int main() { Loader *l = new Loader; Weapon *w; Bomb b; Gun g; w = &b; l->loadFeatures(w); w = &g; l->loadFeatures(w); return 0; }
輸出結(jié)果
裝載武器特性。 裝載武器特性。 裝載武器特性。 裝載武器特性。
我們的實(shí)現(xiàn)似乎是正確的。但是,裝載武器特性被加載了4次。為什么?
最初,武器對(duì)象w指向(Bomb)類的b對(duì)象。 并且,我們嘗試使用l對(duì)象指向(Loader類的)指針將其傳遞給loadFeatures()函數(shù)來(lái)加載Bomb對(duì)象的特性。
同樣,我們嘗試加載Gun對(duì)象的特性。
但是,Loader類的loadFeatures()函數(shù)將指向Weapon類對(duì)象的指針作為參數(shù):
void loadFeatures(Weapon *weapon)
這就是為什么武器特性被加載4次的原因。為了解決這個(gè)問(wèn)題,我們需要使用virtual關(guān)鍵字實(shí)現(xiàn)基類(Weapon類)的虛函數(shù)。
class Weapon { public: virtual void features() { cout << "裝載武器特性。\n"; } };
#include <iostream> using namespace std; class Weapon { public: virtual void features() { cout << "裝載武器特性。\n"; } }; class Bomb : public Weapon { public: void features() { this->Weapon::features(); cout << "裝載刀的特性。\n"; } }; class Gun : public Weapon { public: void features() { this->Weapon::features(); cout << "加載槍的特性。\n"; } }; class Loader { public: void loadFeatures(Weapon *weapon) { weapon->features(); } }; int main() { Loader *l = new Loader; Weapon *w; Bomb b; Gun g; w = &b; l->loadFeatures(w); w = &g; l->loadFeatures(w); return 0; }
輸出結(jié)果
裝載武器特性。 裝載刀的特性。 裝載武器特性。 加載槍的特性。
另外,注意,l->loadFeatures(w)函數(shù)會(huì)根據(jù)l對(duì)象所指向的對(duì)象調(diào)用不同類的函數(shù)。
使用虛函數(shù)使我們的代碼不僅更加清晰,而且更加靈活。
在以上程序中,“裝載武器特性?!北淮蛴×藘纱?。我們建議您在上述程序上添加其他代碼,以便只加載一次武器特性。
如果我們想添加另一種武器(比如說(shuō) 弓),我們可以輕松地添加和加載其特性。如何添加?
class Bow : public Weapon { public: void features() { this-<Weapon::features(); cout >> "加載弓的特性。\n"; } };
并且,在main()函數(shù)中添加如下代碼。
Bow b; w = &b; l->loadFeatures(w);
值得注意的是,我們沒(méi)有更改Loader類中的任何內(nèi)容來(lái)加載刀的特性。
面向?qū)ο缶幊痰哪康氖菍⒁粋€(gè)復(fù)雜的問(wèn)題分成幾個(gè)小集合。這有助于有效理解和處理問(wèn)題。
有時(shí),最好僅在更好地可視化問(wèn)題的情況下使用繼承。
在C ++中,您可以創(chuàng)建一個(gè)無(wú)法實(shí)例化的抽象類(您不能創(chuàng)建該類的對(duì)象)。但是,您可以從中派生一個(gè)類并實(shí)例化派生類的對(duì)象。
抽象類是無(wú)法實(shí)例化的基類。
包含純虛函數(shù)的類稱為抽象類。
聲明以結(jié)尾的=0虛函數(shù)稱為純虛函數(shù)。例如,
class Weapon { public: virtual void features() = 0; };
在這里,純虛函數(shù)是
virtual void features() = 0
并且,該類Weapon是抽象類。
#include <iostream> using namespace std; // 抽象類(不允許實(shí)例化的類) class Shape { protected: float l; public: void getData() { cin >> l; } // 虛函數(shù) virtual float calculateArea() = 0; }; class Square : public Shape { public: float calculateArea() { return l*l; } }; class Circle : public Shape { public: float calculateArea() { return 3.14*l*l; } }; int main() { Square s; Circle c; cout << "輸入長(zhǎng)度來(lái)計(jì)算正方形的面積: "; s.getData(); cout<<"正方形的面積: " << s.calculateArea(); cout<<"\n輸入半徑以計(jì)算圓的面積: "; c.getData(); cout << "圓的面積: " << c.calculateArea(); return 0; }
輸出結(jié)果
輸入長(zhǎng)度來(lái)計(jì)算正方形的面積: 4 正方形的面積: 16 輸入半徑以計(jì)算圓的面積: 5 圓的面積: 78.5
在此程序中,純虛函數(shù)virtual float area()= 0; 在Shape類中定義。
需要注意的一件事是,您應(yīng)該在派生類中重寫基類的純虛函數(shù)。 如果重寫失敗,則派生類也將成為抽象類。