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;