C++類對象空指針訪問成員函數(不報錯)

Demo 

class A{
    public:
    void test(){printf("test A");}
};
int main(){
    A*pA=NULL;
    pA->test();
}

結果是輸出“test A”而不是程序崩潰,原因如下:

一種解釋:

A*pA=null;
pA->test();//當調用成員函數時,只是將實參null傳給this指針

test成員函數中並無任何需要通過this指針訪問的數據成員,因此沒有帶來任何影響

會崩潰的情況,調用的成員函數需要通過this指針訪問類的數據成員變量

#include<stdio.h>

class A{
public:
    void test1(){ printf("test 1"); }
    void test2(){ printf("test 2%d",data); }

private:
    int data = 10;
};
int main(){
    A*pA = NULL;
    pA->test1();//成功輸出”test 1"
    pA->test2();//程序崩潰(注意不是編譯錯誤)

    return 0;
}

結果:運行時崩潰
0x00E013E8 處有未經處理的異常(在 code_test.exe 中): 0xC0000005: 讀取位置 0x00000000 時發生訪問衝突。

 

更詳細的解釋:從c++靜態綁定談起

因爲對於非虛成員函數,C++這門語言是靜態綁定的。這也是C++語言和其它語言Java, Python的一個顯著區別。以此下面的語句爲例:

pA->test();
這語句的意圖是:調用對象 pA 的 test 成員函數。如果這句話在Java或Python等動態綁定的語言之中,編譯器生成的代碼大概是:

找到 pA 的 test 成員函數,調用它。(注意,這裏的找到是程序運行的時候才找的,這也是所謂動態綁定的含義:運行時才綁定這個函數名與其對應的實際代碼。有些地方也稱這種機制爲遲綁定,晚綁定。)

但是對於C++。爲了保證程序的運行時效率,C++的設計者認爲凡是編譯時能確定的事情,就不要拖到運行時再查找了。所以C++的編譯器看到這句話會這麼幹:
1. 查找 pA 的類型,發現它有一個非虛的成員函數叫 test 。(編譯器乾的)
2. 找到了,在這裏生成一個函數調用,直接調A:: test ( pA )。

所以到了運行時,由於 test ()函數裏面並沒有任何需要解引用 pA 指針的代碼,所以真實情況下也不會引發segment fault。這裏對成員函數的解析,和查找其對應的代碼的工作都是在編譯階段完成而非運行時完成的,這就是所謂的靜態綁定,也叫早綁定。

正確理解C++的靜態綁定可以理解一些特殊情況下C++的行爲。 

 

 

轉載自:https://blog.csdn.net/hyqsong/article/details/52136839 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章