C++——對靜態綁定的理解
阿新 • • 發佈:2018-07-24
語句 類型 return font ron ati 成員變量 分析 意圖
但是對於C++。為了保證程序的運行時效率,C++的設計者認為凡是編譯時能確定的事情,就不要拖到運行時再查找了。所以C++的編譯器看到這句話會這麽幹:
1:查找 pA 的類型,發現它有一個非虛的成員函數叫 test 。(編譯器幹的)
2:找到了,在這裏生成一個函數調用,直接調A:: test ( pA )。
所以到了運行時,由於 test ()函數裏面並沒有任何需要解引用 pA 指針的代碼,所以真實情況下也不會引發segment fault。這裏對成員函數的解析,和查找其對應的代碼的工作都是在編譯階段完成而非運行時完成的,這就是所謂的靜態綁定,也叫早綁定。
正確理解C++的靜態綁定可以理解一些特殊情況下C++的行為。
看一個靜態綁定的例子:
1 #include <iostream>
2
3 using namespace std;
4
5 class A
6 {
7 public:
8 int a = 3;
9 void test1()
10 {
11 printf("test A\n");
12 }
13 void test2()
14 {
15 cout << a;
16 }
17 };
18
19 int main()
20 {
21 A *pA = NULL;
22 cout << pA.a; //錯誤:NULL指針不能訪問類非static的成員變量
23 pA -> test1(); //正確:輸出test A
24 pA -> test2(); //錯誤:NULL指針不能訪問類非static的成員變量
25 return 0;
26 }
分析: 由於test是非虛函數,對於非虛成員函數,C++是靜態綁定的,即在編譯時就確定了,即編譯器在編譯的時候就知道。空對象指針不能訪問非static成員變量,但可以訪問成員函數( 非虛函數 ),因為數據成員要分配內存才能訪問,而函數是不需要的。
解析(1):
pA->test1 ;這語句的意圖是:調用對象 pA 的 test 成員函數。如果這句話在Java或Python等動態綁定的語言之中,編譯器生成的代碼大概是:
找到 pA 的 test 成員函數,調用它。(註意,這裏的找到是程序運行的時候才找的,這也是所謂動態綁定的含義:運行時才綁定這個函數名與其對應的實際代碼。有些地方也稱這種機制為遲綁定,晚綁定。)
但是對於C++。為了保證程序的運行時效率,C++的設計者認為凡是編譯時能確定的事情,就不要拖到運行時再查找了。所以C++的編譯器看到這句話會這麽幹:
1:查找 pA 的類型,發現它有一個非虛的成員函數叫 test 。(編譯器幹的)
2:找到了,在這裏生成一個函數調用,直接調A:: test ( pA )。
所以到了運行時,由於 test ()函數裏面並沒有任何需要解引用 pA 指針的代碼,所以真實情況下也不會引發segment fault。這裏對成員函數的解析,和查找其對應的代碼的工作都是在編譯階段完成而非運行時完成的,這就是所謂的靜態綁定,也叫早綁定。
正確理解C++的靜態綁定可以理解一些特殊情況下C++的行為。
解析(2):
test函數作為非虛函數,在編譯時就確定了。即使pA為null,但是已經聲明了類型,就知道pA有個test函數,且test函數裏沒有用到成員變量,單單一個打印語句是可以運行成功的。
本題中NULL指針調用成員函數的時候成員函數中沒有成員變量,如果訪問此對象的成員函數,則程序崩潰,因為this指針是NULL
C++——對靜態綁定的理解