首先:強調一個概念
定義一個函數爲虛函數,不代表函數爲不被實現的函數
定義他爲虛函數是爲了允許用基類的指針來調用子類的這個函數
定義一個函數爲純虛函數,才代表函數沒有被實現
定義他是爲了實現一個接口,起到一個規範的作用,規範繼承這個
類的程序員必須實現這個函數。
對繼承的影響:
普通的類(沒有虛函數,純虛函數)就可以被繼承,而且工作的相當好
關於實例化一個類:
有純虛函數的類是不可能生成類對象的,如果沒有純虛函數則可以。
虛函數在多態中間的使用:
虛函數主要實現多態機制,避免二義性問題。多態一般就是通過指向基類的指針來實現的。
父類的指針在運行時刻來調用子類
定義純虛函數就是爲了讓基類不可實例化化,
因爲實例化這樣的抽象數據結構本身並沒有意義.
或者給出實現也沒有意義
實際上我個人認爲純虛函數的引入,是出於兩個目的,
1.爲了安全.因爲避免任何需要明確但是因爲不小心而導致的未知的結果.
提醒子類去做應做的實現.
2.爲了效率,不是程序執行的效率,而是爲了編碼的效率.
1. 普通函數(no-virtual)
普通函數是靜態編譯的,沒有運行時多態,只會根據指針或引用的“字面值”類對象,調用自己的普通函數。
普通函數是父類爲子類提供的“強制實現”。
因此,在繼承關係中,子類不應該重寫父類的普通函數,因爲函數的調用至於類對象的字面值有關。
2. 虛函數(impure virtual)
C++的虛函數主要作用是“運行時多態”,父類中提供虛函數的實現,爲子類提供默認的函數實現。
子類可以重寫父類的虛函數實現子類的特殊化。
如下就是一個父類中的虛函數:
class A
{
public:
virtual void out2(string s)
{
cout<<"A(out2):"<<s<<endl;
}
};
3. 純虛函數(pure virtual)
C++中包含純虛函數的類,被稱爲是“抽象類”。抽象類不能使用new出對象,只有實現了這個純虛函數的子類才能new出對象。
C++中的純虛函數更像是“只提供申明,沒有實現”,是對子類的約束,是“接口繼承”。
C++中的純虛函數也是一種“運行時多態”。
如下面的類包含純虛函數,就是“抽象類”:
class A
{
public:
virtual void out1(string s)=0;
virtual void out2(string s)
{
cout<<"A(out2):"<<s<<endl;
}
};
4. 綜合實例
#include <iostream>
using namespace std;
class A
{
public:
virtual void out1()=0; ///由子類實現
virtual ~A(){};
virtual void out2() ///默認實現
{
cout<<"A(out2)"<<endl;
}
void out3() ///強制實現
{
cout<<"A(out3)"<<endl;
}
};
class B:public A
{
public:
virtual ~B(){};
void out1()
{
cout<<"B(out1)"<<endl;
}
void out2()
{
cout<<"B(out2)"<<endl;
}
void out3()
{
cout<<"B(out3)"<<endl;
}
};
int main()
{
A *ab=new B;
ab->out1();
ab->out2();
ab->out3();
cout<<"************************"<<endl;
B *bb=new B;
bb->out1();
bb->out2();
bb->out3();
delete ab;
delete bb;
return 0;
}