關於虛函式那點破事

2021-09-05 22:08:45 字數 1427 閱讀 7063

如果你是c++程式設計師,我想你可能遇到過這樣的情況:

在debug時,對著乙個函式step into,明明呼叫的是a函式,可是結果卻跳進了b函式。

為什麼,call stack裡顯示的也是明明白白,就是直接進了b函式。百思不得其解,於是你懷疑是不是系統出了問題,是不是編譯器出了問題,是不是偵錯程式出了問題~~~

其實那些玩意不是那麼容易出錯的,先看看你你的a,b函式是不是同乙個類的虛函式,如果是,這極有可能是因為你修改過虛函式而沒有完全編譯引起的。

還沒明白?看看這個例子, 假設你在project1中有乙個名為debuggingnow的類,該類有三個虛函式:

class debuggingnow

;

在project2中你呼叫了其虛函式:

pdbgnow->f2();
之後由於某種需求你在這個類中加入了乙個虛函式:

class debuggingnow

;

pdbgnow->f2()之前被編譯為呼叫類debuggingnow的第二個虛函式,因為是虛函式,其真正呼叫類似於pdbgnow->vtable[1]。因為在加入函式f1_5()後,f1_5成為了該虛表中的第二個函式,但由於沒有重新編譯project2,pdbgnow->f2()的呼叫沒有更新為正確的pdgbnow->vtable[2],所以真正呼叫的是函式f1_5(),與函式名無關。

可能你會認為這種"低階錯誤"根本不會發生在你身上,至少有兩個方法來解決這個問題:

永遠把虛函式加到最後

永遠編譯所有的工程

的確,這兩招在一定程度上是有效的,但讓我們仔細分析一下:

永遠把虛函式加到最後,針對上面這個例子是有用的。可是如果有其他類派生於類debuggingnow,即使你把虛函式加到了類debuggingnow的最後,還是會打亂其派生類的虛表。

永遠編譯所有的工程,這的確是乙個保險的方法。可是在乙個大型系統中,編譯所有的**所耗費的時間是非常大的,加了乙個虛函式,你可能得等上個好幾個小時才能看到最後的結果,這是我們不願承受的。

那麼,對於大型系統中乙個正處於積極修改期的核心基類,乙個比較好的操作方法是預先分配好足夠多的虛函式,這樣之後需要加虛函式是,只要修改乙個原有的就行了,無需大規模的rebuild ,只需編譯一下用到了這個虛函式的**就可以了。可以說節省的時間是相當可觀的:

class debuggingnow

;

只要靈活運用dummyvirtualfunction,你不光可以運用於加虛函式,也可以在刪虛函式時發揮其作用。

記住兩個操作原則:

當dummyvirtualfunction快用完時,再預先分配一些。

當這一階段開發結束時,該基類趨於穩定,把多餘的dummyvirtualfunction去掉就可以了。

SPI匯流排那點破事

spi為序列外設介面的縮寫,spi為高速全雙工同步通訊匯流排,共使用4根線。spi以主從方式工作,通常可以乙個主裝置和乙個或多個從裝置。需要至少4根線。miso 主裝置資料輸入 mosi 主裝置資料輸出 sclk 時鐘 cs 片選 cs是從裝置是否被主裝置選中的引腳,當被選中時 通常以cs為低電平選...

談談VIP漂移那點破事

一直以來都是用nginx的upstream模組做 最前端的負載均衡,為了防止nginx本身宕機導致 不能訪問,通常都會做兩套nginx反向 然後用keepalive之類的軟體提供vip。常見的環境是nginx主節點和從節點各有乙個公網ip,乙個私有ip,vip位址也使用公網ip來提供,正常情況下vi...

談談VIP漂移那點破事

一直以來都是用nginx的upstream模組做 最前端的負載均衡,為了防止nginx本身宕機導致 不能訪問,通常都會做兩套nginx反向 然後用keepalive之類的軟體提供vip。常見的環境是nginx主節點和從節點各有乙個公網ip,乙個私有ip,vip位址也使用公網ip來提供,正常情況下vi...