某一天寫程式,調試時突然出現如下的錯誤提示:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
我很少遇到類似的C++運行時檢查錯誤,至於什麼堆棧指標丟失就更不用說啦,因為我寫的代碼全是按照C++預設的函數呼叫慣例,應該不會出現函式宣告和函數指標定義的呼叫慣例不一致的情況。
問題總是要解決的。跟蹤代碼,發現每次調用IComm對象的函數時就出現該錯誤。查看該對象的狀態,發現IComm的子類狀態亂七八槽,不是預期的狀態。
這裡先說一下類的結構。
IComm: 通訊器介面,抽象類別
ISerial: 串口通訊介面,抽象類別
CSerial: 串口通訊對象,同時實現IComm和ISerial介面(繼承自IComm和ISerial)
我是這樣初始化的:
ISerial * pSerial = new CSerial(); // 語句1
pSerial->SetPort(4);
pSerial->SetBaud(19200);
IComm * pComm = (IComm *) pSerial; // 語句2
// 儲存pSerial和pComm
跟蹤發現,執行語句2後,pSerial的CSerial子類狀態是Port=4, Baud=19200;而pComm的CSerial子類狀態卻不是!
把語句2改為:
IComm * pComm = (CSerial *) pSerial;
後,狀態正確了,Run-Time Check Failure #0 也消失了。
分析:C++在父類子類相互類型轉換的時候,如果不正確地指定轉換路徑,那麼,對象的子類狀態和函數入口地址等記憶體將錯位,所以運行時類型檢查時,出現堆積指標丟失的錯誤,而不是什麼函數呼叫慣例不一致。
出現這種錯誤是由於我對C++的類型轉換不熟悉的結果。我一直使用C的類型轉換樣式,我想當然以為C++會幫我們把父子類類型轉換路徑完全做好。以後要複習一下C++類型轉換了。