注:
對靜態函數或靜態成員的調用方式不做分析;
以下提到的測試環境為vc6.0;
調試程序時看到這樣的代碼:
1 pObj->ClassName::Function();
開始不理解為什麼要在“->”後加上類名“ClassName::”,一般使用中類名稱加“::”(ClassName::)是用來調用靜態函數或靜態成員的,帶著疑問做了下嘗試。
定義類A:
1 class A 2 { 3 public: 4 void Test() 5 { 6 int nVal= 8; 7 int nVal1 = nVal; 8 } 9 10 };
調用方式:
1 A* pA = NULL; 2 pA->A::Test();
測試能夠順利通過。但是調試時進入A類的Test()函數發現this指針為空:
修改類A為:
1 class A 2 { 3 public: 4 A(){ m_nVal = 5; } 5 ~A(){} 6 7 void Test() 8 { 9 int nVal= 8; 10 int nVal1 = nVal; 11 int nVal2 = m_nVal; //調用成員變量 12 13 } 14 15 protected: 16 int m_nVal; //增加成員變量 17 18 };
再次執行:
1 A* pA = NULL; 2 pA->A::Test();
這次程序會崩潰,調試發現是在使用成員變量時崩潰,如下圖:
通過上面的測試初步得出結論,當采用pA->A::Test()這種方式進行調用時,如果Test()函數中沒有使用類的非靜態成員變量,調用的指針(具體的類對象指針this)是否為空可以不考慮,能夠順利通過,如果Test()函數中使用了類的非靜態成員變量,則必須要求調用的指針不為null,也就是必須有已分配了內存空間的類對象,因為這些非靜態成員變量的空間是分配在類對象上的。對於類的靜態成員這裡就不在敘述(因為類的靜態成員屬於類本身,不屬於類對象)。
到這裡問題就來了,調用時直接寫成pA->Test()不就可以了,干嘛寫的這麼別扭,給人感覺很深奧的樣子(事實是有點深奧),通過經驗猜測應該和繼承有關系,於是做了如下嘗試:
修改類A:
1 class A 2 { 3 public: 4 A(){ m_nVal = 5; } 5 ~A(){} 6 7 virtual void Test() //變為虛函數 8 { 9 int nVal= 8; 10 int nVal1 = nVal; 11 int nVal2 = m_nVal; 12 } 13 14 protected: 15 int m_nVal; 16 };
增加類B繼承於類A:
1 class A 2 { 3 public: 4 A(){ m_nVal = 5; } 5 ~A(){} 6 7 virtual void Test() //變為虛函數 8 { 9 int nVal= 8; 10 int nVal1 = nVal; 11 int nVal2 = m_nVal; 12 } 13 14 protected: 15 int m_nVal; 16 };
調用方式:
A* pA = new B;
pA->Test(); //第一步
pA->A::Test(); //第二步
調試時發現,當執行第一步時進入的是類B(子類)中定義的Test()函數,執行第二步時進入的是類A(父類)中的Test()函數,第一步調用是實現多態的一種方式很常見,而第二種調用方式是刻意破壞多態的結構,已達到指定的去執行父類的函數,我個人不贊成這種寫法,首先它打破了常規寫法,並且看起來不易理解,也不利於維護擴展,完全可以采取其他常見方式實現相應功能。