詳解C++純虛函數(shù)與抽象類
1.虛函數(shù)
1.1虛函數(shù)簡介
虛函數(shù)可以毫不夸張的說是C++最重要的特性之一,我們先來看一看虛函數(shù)的概念。
在基類的定義中,定義虛函數(shù)的一般形式為:
virtual 函數(shù)返回值類型 虛函數(shù)名(形參表)
{
函數(shù)體
}
為什么說虛函數(shù)是C++最重要的特性之一呢,因為虛函數(shù)承載著C++中動態(tài)聯(lián)編的作用,也即多態(tài),可以讓程序在運行時選擇合適的成員函數(shù)。虛函數(shù)必須是類的非靜態(tài)成員函數(shù)(且非構造函數(shù)),其訪問權限是public。那么:
(1)為什么類的靜態(tài)成員函數(shù)不能為虛函數(shù)?
如果定義為虛函數(shù),那么它就是動態(tài)綁定的,也就是在派生類中可以被覆蓋的,這與靜態(tài)成員函數(shù)的定義(在內(nèi)存中只有一份拷貝,通過類名或?qū)ο笠迷L問靜態(tài)成員)本身就是相矛盾的。
(2)為什么構造函數(shù)不能為虛函數(shù)?
因為如果構造函數(shù)為虛函數(shù)的話,它將在執(zhí)行期間被構造,而執(zhí)行期則需要對象已經(jīng)建立,構造函數(shù)所完成的工作就是為了建立合適的對象,因此在沒有構建好的對象上不可能執(zhí)行多態(tài)(虛函數(shù)的目的就在于實現(xiàn)多態(tài)性)的工作。在繼承體系中,構造的順序就是從基類到派生類,其目的就在于確保對象能夠成功地構建。構造函數(shù)同時承擔著虛函數(shù)表的建立,如果它本身都是虛函數(shù)的話,又如何確保虛函數(shù)表的成功構建呢?
1.2虛析構函數(shù)
在類的繼承中,基類的析構函數(shù)一般都是虛函數(shù)。當基類中有虛函數(shù)的時候,析構函數(shù)也要定義為虛析構函數(shù)。如果不定義虛析構函數(shù),當刪除一個指向派生類對象的指針時,會調(diào)用基類的析構函數(shù),派生類的析構函數(shù)未被調(diào)用,造成內(nèi)存泄露。
虛析構函數(shù)工作的方式是:最底層的派生類的析構函數(shù)最先被調(diào)用,然后各個基類的析構函數(shù)被調(diào)用。這樣,當刪除指向派生類的指針時,就會首先調(diào)用派生類的析構函數(shù),不會有內(nèi)存泄露的問題了。
一般情況下,如果類中沒有虛函數(shù),就不用去聲明虛析構函數(shù)。當且僅當類里包含至少一個虛函數(shù)的時候才去聲明虛析構函數(shù)。只有當一個類被用來作為基類的時候,才有必要將析構函數(shù)寫成虛函數(shù)。
1.3虛函數(shù)的實現(xiàn)——虛函數(shù)表
虛函數(shù)是通過一張?zhí)摵瘮?shù)表來實現(xiàn)的,簡稱V-Table。類的虛函數(shù)表是一塊連續(xù)的內(nèi)存,每個內(nèi)存單元中記錄一個JMP指令的地址。編譯器會為每個有虛函數(shù)的類創(chuàng)建一個虛函數(shù)表,該虛函數(shù)表將被該類的所有對象共享,類的每個虛函數(shù)成員占據(jù)虛函數(shù)表中的一行。
在這個表中,存放的是一個類的虛函數(shù)的地址。這張表解決了繼承、覆蓋的問題,保證使用指向子類對象實體的基類指針或引用,能夠訪問到對象實際的虛函數(shù)。在有虛函數(shù)類的實例中,分配了指向這個表的指針的內(nèi)存,所以,當用父類的指針來操作一個子類對象實體的時候,這張?zhí)摵瘮?shù)表就指明了實際所應該被調(diào)用的虛函數(shù)。
2.純虛函數(shù)與抽象類
既然有了虛函數(shù),那為什么還需要有純虛函數(shù)呢?在Java編程語言中有接口的定義,在C++中雖然沒有接口關鍵字,但是純虛函數(shù)就完成了接口的功能。而且有時在編寫基類的時候,發(fā)生了如下情況:
(1)功能不應由基類去完成;
(2)還沒想好應該如何寫基類的這個函數(shù);
(3)有的時候基類本身不應被實例化。
這時就可以用到純虛函數(shù)了。下面我們通過一個例子比較虛函數(shù)和純虛函數(shù)的區(qū)別:
class Base
{
public:
//這是一個虛函數(shù)
virtual void vir_func()
{
cout << "This is a virtual function of Base" << endl;
}
//這是一個純虛函數(shù)
virtual void pure_vir_func() = 0;
};
由上可見,純虛函數(shù)在類中沒有定義函數(shù)體,并加上了“= 0”。而含有至少一個純虛函數(shù)的類被稱為抽象類。定義純虛函數(shù)和抽象類的目的在于,僅僅只定義派生類繼承的接口,而暫時無法提供一個合理的缺省實現(xiàn)。所以純虛函數(shù)的聲明就是在告訴子類的設計者,“你必須實現(xiàn)這個函數(shù),但我不知道你會怎樣實現(xiàn)它”。
值得特別注意的是,由于抽象類至少有一個函數(shù)沒有實現(xiàn),所以抽象類無法被實例化,否則編譯器會報錯。
下面看一下純虛函數(shù)與抽象類的實例。本實驗在GNU C++環(huán)境下進行。
#include <iostream>
using namespace std;
class Base
{
public:
//這是一個虛函數(shù)
virtual void vir_func()
{
cout << "This is a virtual function of Base" << endl;
}
//這是一個純虛函數(shù)
virtual void pure_vir_func() =0;
};
class Derive : Base
{
public:
void vir_func()
{
cout << "This is a virtual function of Derive" << endl;
}
void pure_vir_func()
{
cout << "This is a pure virtual function of Derive" << endl;
}
};
int main()
{
// Base b; //企圖實例化抽象類,編譯器報錯
// b.vir_func();
Derive d;
d.vir_func();
d.pure_vir_func();
return 0;
}
輸出:
This is a virtual function of Derive
This is a pure virtual function of Derive
派生類Derive實現(xiàn)了基類Base類的虛函數(shù)和純虛函數(shù),同時注意到,企圖去實例化抽象類,編譯器會報錯。
一般而言,純虛函數(shù)沒有函數(shù)體,但是也可以給出純虛函數(shù)的函數(shù)體,所以下面這樣的結構是可以通過編譯的:
class Base
{
public:
//這是一個虛函數(shù)
virtual void vir_func()
{
cout << "This is a virtual function of Base" << endl;
}
//這是一個純虛函數(shù)
virtual void pure_vir_func() =0
{
cout << "This is a pure virtual function of Base" << endl;
}
};
但這樣做并沒有什么意義,因為抽象類并不能實例化,不能調(diào)用該方法。
以上就是詳解C++純虛函數(shù)與抽象類的詳細內(nèi)容,更多關于C++純虛函數(shù)與抽象類的資料請關注腳本之家其它相關文章!
相關文章
劍指offer之C語言不修改數(shù)組找出重復的數(shù)字
今天小編就為大家分享一篇關于劍指offer之C語言不修改數(shù)組找出重復的數(shù)字,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-02-02
VisualStudio2022不支持.NET Framework 4.0項目解決辦法
本文主要介紹了VisualStudio2022不支持.NET Framework 4.0項目解決辦法,文中通過圖文的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-09-09

