你了解c 中的關鍵字virtual嗎?

2021-10-05 08:32:17 字數 3410 閱讀 7730

virtual在英文中表示「虛」、「虛擬」的含義。c++中的關鍵字「virtual」主要用在兩個方面:虛函式與虛基類。下面將分別從這兩個方面對virtual進行介紹。

虛函式源於c++中的類繼承,是多型的一種。在c++中,乙個基類的指標或者引用可以指向或者引用派生類的物件。同時,派生類可以重寫基類中的成員函式。這裡「重寫」的要求是函式的特徵標(包括引數的數目、型別和順序)以及返回值都必須與基類中的函式一致。如下所示:

class

base

virtual

~base()

};class

inheriter

:public base

//重寫基類方法

};

可以在基類中將被重寫的成員函式設定為虛函式,其含義是:當通過基類的指標或者引用呼叫該成員函式時,將根據指標指向的物件型別確定呼叫的函式,而非指標的型別。如下,是未將test()函式設定為虛函式前的執行結果:

base *p1=

new base;

base *p2=

new inheriter;

p1->

test()

;//輸出「基類方法」

p2->

test()

;//輸出「基類方法」

在將test()函式設定為virtual後,執行結果如下:

base *p1=

new base;

//p1指向base類

base *p2=

new inheriter;

//p2指向inheriter類

p1->

test()

;//輸出「基類方法」

p2->

test()

;//輸出「派生類方法」

如此,便可以將基類與派生類的同名方法區分開,實現多型。

說明:

1.只需將基類中的成員函式宣告為虛函式即可,派生類中重寫的virtual函式自動成為虛函式;

2.基類中的析構函式必須為虛函式,否則會出現物件釋放錯誤。以上例說明,如果不將基類的析構函式宣告為virtual,那麼在呼叫delete p2;語句時將呼叫基類的析構函式,而不是應當呼叫的派生類的析構函式,從而出現物件釋放錯誤的問題。

3.虛函式的使用將導致類物件占用更大的記憶體空間。對這一點的解釋涉及到虛函式呼叫的原理:編譯器給每乙個包括虛函式的物件新增了乙個隱藏成員:指向虛函式表的指標。虛函式表(virtual function table)包含了虛函式的位址,由所有虛函式物件共享。當派生類重新定義虛函式時,則將該函式的位址新增到虛函式表中。無論乙個類物件中定義了多少個虛函式,虛函式指標只有乙個。相應地,每個物件在記憶體中的大小要比沒有虛函式時大4個位元組(32位主機,不包括虛析構函式)。如下:

cout<<

sizeof

(base)

cout<<

sizeof

(inheriter)

base類中包括了兩個整型的成員變數,各佔4個位元組大小,再加上乙個虛函式指標,共計佔12個位元組;inheriter類繼承了base類的兩個成員變數以及虛函式表指標,因此大小與基類一致。如果inheriter多重繼承自另外乙個也包括了虛函式的基類,那麼隱藏成員就包括了兩個虛函式表指標。

4.重寫函式的特徵標必須與基類函式一致,否則將覆蓋基類函式;

5.重寫不同於過載。我對過載的理解是:同乙個類,內部的同名函式具有不同的引數列表稱為過載;重寫則是派生類對基類同名函式的「本地改造」,要求函式特徵標完全相同。當然,返回值型別不一定相同(可能會出現返回型別協變的特殊情況)。

在c++中,派生類可以繼承多個基類。問題在於:如果這多個基類又是繼承自同乙個基類時,那麼派生類是不是需要多次繼承這「同乙個基類」中的內容?虛基類可以解決這個問題。

簡而言之,虛基類可以使得從多個類(它們繼承自乙個類)中派生出的物件只繼承乙個物件。虛繼承的寫法如下:

class

mytest

:virtual

public base

;

base稱為mytest類的虛基類。假設base還是另外乙個類mytest2的虛基類,對於多重繼承mytest和mytest2的子類mytest3而言,base的部分只繼承了一次。如下:

class

base

virtual

~base()

;};class

mytest

:virtual

public base

;class

mytest2

:virtual

public base

;class

mytest3

:public mytest,

public mytest2;

cout<<

sizeof

(mytest)

cout<<

sizeof

(mytest2)

cout<<

sizeof

(mytest3)

mytest類與mytest2類的大小為什麼是12?這是因為它們在虛繼承自base類後,新增了乙個隱藏的成員——指向虛基類的指標,佔4個位元組。而base類本身佔8個位元組,因此它們的大小均為12。而對非虛繼承而言,是不需要這樣的乙個指標的。而mytest3類的大小為sizeof(base)+sizeof(mytest-base)+sizeof(mytest2-base),即16。

說明:

1.若乙個類多重繼承自具有同乙個基類的派生類時,呼叫同名成員函式時會出現二義性。為了解決這個問題,可以通過作用域解析運算子澄清,或者在類中進行重新定義;

2.繼承關係可能是非常繁複的。乙個類可能多重繼承自別的類,而它的父類也可能繼承自別的類。當該類從不同的途徑繼承了兩個或者更多的同名函式時,如果沒有對類名限定為virtual,將導致二義性。當然,如果使用了虛基類,則不一定會導致二義性。編譯器將選擇繼承路徑上「最短」的父類成員函式加以呼叫。該規則與成員函式的訪問控制許可權並不矛盾。也就是說,不能因為具有更高呼叫優先順序的成員函式的訪問控制許可權是"private",而轉而去呼叫public型的較低優先順序的同名成員函式。

當然,宣告為純虛函式並不意味著在實現檔案中不可對其進行定義,只是意味著不可用抽象基類實現乙個具體的物件。

virtual在英文中表示「虛」、「虛擬」的含義。c++中的關鍵字「virtual」主要用在兩個方面:虛函式與虛基類。下面將分別從這兩個方面對virtual進行介紹。

你了解c 中的關鍵字virtual嗎?

virtual在英文中表示 虛 虛擬 的含義。c 中的關鍵字 virtual 主要用在兩個方面 虛函式與虛基類。下面將分別從這兩個方面對virtual進行介紹。虛函式源於c 中的類繼承,是多型的一種。在c 中,乙個基類的指標或者引用可以指向或者引用派生類的物件。同時,派生類可以重寫基類中的成員函式。...

你了解this和super關鍵字嗎

this表示指向當前例項物件,區分物件的成員變數和方法形參 當方法的形參和成員變數的名字重名,可以使用this.變數名呼叫此類的成員變數 public class test public static void setage int age 子類用來呼叫父類的成員變數或方法。當子類的成員變數或方法與...

synchronized 關鍵字的了解

synchronized 關鍵字的介紹 synchronized關鍵字解決的是多個執行緒之間訪問資源的同步性,synchronized關鍵字可以保證被它修飾的方法或者 塊在任意時刻只能有乙個執行緒執行。例如每個執行緒表示乙個視窗 一張票,那麼用了這個關鍵字之後全世界在同一時刻只有乙個人在進行買票操作...