在本文中,您將了解虛函數(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ù)。 如果重寫失敗,則派生類也將成為抽象類。