最近在查
CWnd::GetSafeHwnd()
函數時,順帶發現了一個關于
CWnd::GetSafeHwnd()
的實作過程的讨論,其中讨論過程涉及到了空指針調用成員函數的問題,恰巧之前工作項目中也有偶遇到相關的知識,是以在此總結一下相關知識。
總結到的相關知識
- 空對象指針(NULL)可以正常調用成員函數, 并正常傳回值
- 空對象指針(NULL)調用成員函數時,如果通路對象的成員變量,會崩潰
- 空對象指針(NULL)調用類的虛函數會崩潰
- 對于包含虛函數的類,其每個對象指針都含有一個隐藏的成員變量,虛函數表指針
vfptr
實驗工具
類聲明:
class CStringHelper
{
public:
CStringHelper();
virtual ~CStringHelper();
int DoNothing();
void SetStringFlag();
virtual int DoVirtualFunc();
protected:
int m_nStringFlag = 1;
static int ms_nCommVar;
};
類實作:
#include "StringHelper.h"
int CStringHelper::ms_nCommVar = 100;
CStringHelper::CStringHelper()
{
}
CStringHelper::~CStringHelper()
{
}
int CStringHelper::DoNothing()
{
int k = 0;
++ms_nCommVar;
return ms_nCommVar;
}
void CStringHelper::SetStringFlag()
{
int x = DoNothing();
m_nStringFlag = 2;
}
int CStringHelper::DoVirtualFunc()
{
int y = DoNothing();
return y;
}
空對象指針(NULL)可以正常調用成員函數, 并正常傳回值
- 實驗過程
CStringHelper *pStringHelper = NULL;
pStringHelper->DoNothing();
pStringHelper->SetStringFlag();
- 實驗結果
- 調用
正常DoNothing
- 調用
過程中,調用SetStringFlag
正常傳回,執行到DoNothin
語句時崩潰m_nStringFlag = 2;
- 調用
- 理論支撐
- 調用普通成員函數時(非靜态成員函數),有一個隐藏的參數是this指針,類的普通成員函數的位址在程式開始執行時已經是一個固定的位址了。隻有通路類的非靜态成員變量時才會使用到this指針(對于成員變量
其實是m_nStringFlag
)。隻有當通路成員變量時,且傳入的this指針為空時才會崩潰。this->m_nStringFlag
- 調用普通成員函數時(非靜态成員函數),有一個隐藏的參數是this指針,類的普通成員函數的位址在程式開始執行時已經是一個固定的位址了。隻有通路類的非靜态成員變量時才會使用到this指針(對于成員變量
空對象指針(NULL)調用成員函數時,如果通路對象的成員變量,會崩潰。
- 同上
空對象指針(NULL)調用類的虛函數會崩潰
- 實驗過程
CStringHelper *pStringHelper = NULL;
pStringHelper->DoVirtualFunc();
- 實驗結果
- 執行到
語句時崩潰pStringHelper->DoVirtualFunc();
- 執行到
對于包含虛函數的類,其每個對象指針都含有一個隐藏的成員變量,虛函數表指針 vfptr
vfptr
- 事實支撐
- 對于擁有虛函數的每個對象,都有一個預設的隐藏成員變量——虛函數表指針
vfptr
- 從VS的
中可以看出:自動變量
而且,相同的類産生的對象的虛函數表指針是否可以使用空對象指針調用成員函數及通路成員變量
都是相同的(可以從實驗結果觀察出該事實)vfptr
- 對于沒有成員變量,有虛函數的類,因為該對象函數一個虛函數表指針,在32位作業系統下,輸出其sizeof,為4:
順帶一提,如果沒有虛函數,sizeof得到的值為1。class CEmptyClass { public: CEmptyClass(); virtual ~CEmptyClass(); };
- 從VS的
- 對于擁有虛函數的每個對象,都有一個預設的隐藏成員變量——虛函數表指針
轉載于:https://www.cnblogs.com/HelloGreen/p/11522263.html