虛函數構造和析構函數執行順序總結


一.定義

虛函數: 在某基類中聲明為 virtual 並在一個或多個派生類中被重新定義的成員函數,可實現函數成員的動態重載。

純虛函數: 純虛函數是一種特殊的虛函數,在許多情況下,在基類中不能對虛函數給出有意義的實現,而把它聲明為純虛函數,它的實現留給該基類的派生類去做。含有純虛函數的類被稱為抽象類(abstract class)


二.格式

虛函數:virtual <函數返回類型>< 函數名>(<參數表>) {函數體};

純虛函數:virtual <函數返回類型><函數名>(<參數表>)=0;

三.不同點

1.虛函數可以直接使用,也可以在子類中重載以多態的形式調用,但純虛函數在基類中只有聲明沒有定義,所以只能在子類中實現了該函數才可以以多態的形式調用。 
2.虛函數在子類中可以不被重載,但是純虛函數必須在子類中實現。 
3.包含純虛函數的類成為抽象類,這種類不能聲明對象,只是作為基類為派生類服務。除非在派生類中完全實現基類中所有的的純虛函數,否則,派生類也變成了抽象類,不能實例化對象。

虛函數以及構造函數執行順序的一些特性(例題)

構造函數:先構造基類,再構造派生類;

析構函數:先析構派生類,再析構基類。

例題一(函數執行順序)

下面這段代碼會打印出什么?

class A
{
public:
    A()
    {
        printf("A ");
    }
    ~A()
    {
        printf("deA ");
    }
};

class B
{
public:
    B()
    {
        printf("B ");
    }
    ~B()
    {
        printf("deB ");
    }
};

class C: public A, public B//按照順序執行構造函數,先執行A,再執行B
{
public:
    C()
    {
        printf("C ");
    }
    ~C()
    {
        printf("deC ");
    }
};
int main()
{
    A *a = new C();//指針不是對象,只有A a這樣才是創建對象
    delete a;
    return 0;
}

正確答案: A 你的答案: B (錯誤)

(A) A B C deA

(B) C A B deA

(C) A B C deC

(D) C A B deC

解析:構造函數的執行先執行父類,再執行子類。析構函數的執行順序相反,A B的析構函數不是虛函數,所以不會執行子類的虛函數。


例題二(函數執行順序)

 

 

解析: 
1.當派生類中不含對象成員時 
在創建派生類對象時,構造函數的執行順序是:基類的構造函數→派生類的構造函數; 
析構函數相反。 
2.當派生類中含有對象成員時 
在定義派生類對象時,構造函數的執行順序:基類的構造函數→對象成員的構造函數→派生類的構造函數; 
析構函數相反。


例題三(虛函數調用順序)

 dynamic_cast里面必須含有虛函數才行,有虛函數的析構函數,才會先析構子類,再析構基類,不然只會析構自己所在的類。

 

 

解析:創建一個類對象c,然后動態類型轉換,讓一個B *b1指針指向c,再一次動態類型轉換,讓一個基類A *a2指針指向b1,當delete a2時,調用析構函數,但是基類A的析構函數不是虛函數,所以只調用A的析構函數,結果應該是:~A() 
動態的多態通過虛函數實現,基類指針指向派生類的對象,若指針調用的函數派生類中存在,且在基類中聲明為虛函數,則調用的函數是派生類中的函數。 析構函數總是要聲明為虛函數,這樣析構時,先調用派生類的析構函數,再調用基類的析構函數,防止內存造成泄露 。A類的析構函數未聲明為虛函數,所以A類的指針,只可以調用A類的析構函數


例題四(純虛函數)

 

 

 解析:純虛函數格式:virtual <類型> <函數名> (<參數表>) = 0;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM