天天看點

是否可以使用空對象指針調用成員函數及通路成員變量

最近在查

CWnd::GetSafeHwnd()

函數時,順帶發現了一個關于

CWnd::GetSafeHwnd()

的實作過程的讨論,其中讨論過程涉及到了空指針調用成員函數的問題,恰巧之前工作項目中也有偶遇到相關的知識,是以在此總結一下相關知識。

總結到的相關知識

  1. 空對象指針(NULL)可以正常調用成員函數, 并正常傳回值
  2. 空對象指針(NULL)調用成員函數時,如果通路對象的成員變量,會崩潰
  3. 空對象指針(NULL)調用類的虛函數會崩潰
  4. 對于包含虛函數的類,其每個對象指針都含有一個隐藏的成員變量,虛函數表指針

    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->m_nStringFlag

      )。隻有當通路成員變量時,且傳入的this指針為空時才會崩潰。

空對象指針(NULL)調用成員函數時,如果通路對象的成員變量,會崩潰。

  • 同上

空對象指針(NULL)調用類的虛函數會崩潰

  • 實驗過程
CStringHelper *pStringHelper = NULL;
    pStringHelper->DoVirtualFunc();
           
  • 實驗結果
    • 執行到

      pStringHelper->DoVirtualFunc();

      語句時崩潰

對于包含虛函數的類,其每個對象指針都含有一個隐藏的成員變量,虛函數表指針

vfptr

  • 事實支撐
    • 對于擁有虛函數的每個對象,都有一個預設的隐藏成員變量——虛函數表指針

      vfptr

      • 從VS的

        自動變量

        中可以看出:
        是否可以使用空對象指針調用成員函數及通路成員變量
        而且,相同的類産生的對象的虛函數表指針

        vfptr

        都是相同的(可以從實驗結果觀察出該事實)
      • 對于沒有成員變量,有虛函數的類,因為該對象函數一個虛函數表指針,在32位作業系統下,輸出其sizeof,為4:
      class CEmptyClass
      {
      public:
        CEmptyClass();
         virtual ~CEmptyClass();
      };
                 
      順帶一提,如果沒有虛函數,sizeof得到的值為1。

轉載于:https://www.cnblogs.com/HelloGreen/p/11522263.html

繼續閱讀