今天在做一道面試題的時候遇到一個純虛函數的概念,就翻了下書,查資料,對比下虛函數,現在整理一下和大家分享:
什么是虛函數?
那些被virtual關鍵字修飾的成員函數,就是虛函數。虛函數的作用,用專業術語來解釋就是實現多態性(Polymorphism),多態性是將接口與實現進行分離;用形象的語言來解釋就是實現以共同的方法,但因個體差異而采用不同的策略。
虛函數聲明如下:virtual ReturnType FunctionName(Parameter);
虛函數必須實現,如果不實現,編譯器將報錯,錯誤提示為:
error LNK****: unresolved external symbol "public: virtual void __thiscall
ClassName::virtualFunctionName(void)"
為什么要用純虛函數?
在很多情況下,基類本身生成對象是不合情理的。例如,動物作為一個基類可以派生出老虎、孔雀等子類,但動物本身生成對象明顯不合常理。為了解決這個問題,方便使用類的多態性,引入了純虛函數的概念,將函數定義為純虛函數(方法:virtual ReturnType Function()= 0;),則編譯器要求在派生類中必須予以重寫以實現多態性。同時含有純虛擬函數的類稱為抽象類,它不能生成對象。
在什么情況下使用純虛函數(pure vitrual function)?
1,當想在基類中抽象出一個方法,且該基類只做能被繼承,而不能被實例化;
2,這個方法必須在派生類(derived class)中被實現;
如果滿足以上兩點,可以考慮將該方法申明為pure virtual function.
我們來舉個例子,我們先定義一個形狀的類(Cshape),但凡是形狀我們都要求其能顯示自己。所以我們定義了一個類如下:
class CShape
{
virtual void Show()
{};
};
但沒有CShape這種形狀,因此我們不想讓CShape這個類被實例化,我們首先想到的是將Show函數的定義(實現)部分刪除如下:
class CShape
{
virtual void Show();
};
當我們使用下面的語句實例化一個CShape時:
CShape cs; //這是我們不允許的,但僅用上面的代碼是可以通過編譯(但link時失敗)。
怎么樣避免一個CShape被實例化,且在編譯時就被發現?
答案是:使用pure virtual funcion.
我們再次修改CShape類如下:
class CShape
{
public:
virtual void Show()
=0;
};
這時在實例化CShape時就會有以下報錯信息:
error C2259: 'CShape' : cannot instantiate abstract class due to following members:
warning C4259: 'void __thiscall CShape::Show(void)' : pure virtual function was not defined
我們再來看看被繼承的情況,我們需要一個CPoint2D的類,它繼承自CShape.他必須實現基類(CShape)中的Show()方法。
其實使用最初的本意是讓每一個派生自CShape的類,都要實現Show()方法,但時常我們可能在一個派生類中忘記了實現Show(),為了避免這種情況,pure virtual funcion發揮作用了。
我們看以下代碼:
class CPoint2D:public CShape
{
public:
CPoint2D()
{
printf("CPoint2D ctor is invoked\n");
};
void Msg()
{
printf("CPoint2D.Msg() is invoked\n");
};
{
public:
CPoint2D()
{
printf("CPoint2D ctor is invoked\n");
};
void Msg()
{
printf("CPoint2D.Msg() is invoked\n");
};
};
當我們實例化CPoint2D時,在編譯時(at the compiling)也會出現如下的報錯:
error C2259: 'CShape' : cannot instantiate abstract class due to following members:
warning C4259: 'void __thiscall CShape::Show(void)' : pure virtual function was not defined
如上,我們預防了在派生類中忘記實現基類方法。