1. 程式人生 > >C++虛擬函式與函式的執行順序

C++虛擬函式與函式的執行順序

一.定義

虛擬函式: 在某基類中宣告為 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 { public: C() { printf("C "); } ~C() { printf("deC "); } }; int
main() { A *a = new C(); delete a; return 0; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

正確答案: 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.當派生類中含有物件成員時 
在定義派生類物件時,建構函式的執行順序:基類的建構函式→物件成員的建構函式→派生類的建構函式; 
解構函式相反。

例題三(虛擬函式呼叫順序)

這裡寫圖片描述
這裡寫圖片描述

解析:建立一個類物件c,然後動態型別轉換,讓一個B *b1指標指向c,再一次動態型別轉換,讓一個基類A *a2指標指向b1,當delete a2時,呼叫解構函式,但是基類A的解構函式不是虛擬函式,所以只調用A的解構函式,結果應該是:~A() 
動態的多型通過虛擬函式實現,基類指標指向派生類的物件,若指標呼叫的函式派生類中存在,且在基類中宣告為虛擬函式,則呼叫的函式是派生類中的函式。 解構函式總是要宣告為虛擬函式,這樣析構時,先呼叫派生類的解構函式,再呼叫基類的解構函式,防止記憶體造成洩露 。A類的解構函式未宣告為虛擬函式,所以A類的指標,只可以呼叫A類的解構函式

例題四(純虛擬函式)

這裡寫圖片描述
解析:純虛擬函式格式:virtual <型別> <函式名> (<引數表>) = 0;