萬惡的void 指標型別轉換

2021-07-02 11:54:34 字數 2291 閱讀 2841

大家都知道:用乙個基類的指標指向乙個派生類的物件是合理的,然而很多人卻忽略了這樣做的大前提:必須使用規範的指標轉換過程。

最近要新增乙個功能,上層**為此新增了乙個虛函式介面。我一看,此虛函式所在的類也是新增的,底層驅動**以前沒有使用過這個類。

class idmial_ver5

};但是驅動現有乙個cdrvadaptdm類。問了問上層,他們說直接用現有的類繼承idmial_ver5這個父類,然後實現新增的ial_setrldramcondition虛函式就可以了。以後上層呼叫這個虛函式的時候,就會自動呼叫到驅動的實現**。

於是我就給cdrvadaptdm新增了乙個父類,一切看起來都很正常:

class cdrvadaptdm : public idmial, public idrvadpmodule, public idmial_ver5

搞定,編譯軟體,上板測試,結果——單板起不來!

我連上串列埠看,每次啟動中都會出現這麼個錯誤,然後單板就再次復位了:

program

exception current instruction address: 0x00000000

machine status register: 0x0008b032

condition register: 0x40004085

task: 0x4334460 "tbdptccmd"

經過一番定位,發現是在上層軟體呼叫這個新的介面時復位的。奇怪了,繼承乙個父類,實現其虛函式難道有問題嗎?打斷點看看上層在呼叫時,傳入的this指標,也確實就是cdrvadaptdm物件的指標沒錯。突然,我想到:難道是多重繼承搗的鬼?

於是,我寫了一段**,測試一下用父類的指標呼叫子類的虛函式:(g_pdrvadaptdm是cdrvadaptdm物件的全域性指標)

printf("g_pdrvadaptdm = %#x", (unsigned int)g_pdrvadaptdm);

idmial_ver5* pver5 = dynamic_cast(g_pdrvadaptdm);

printf("ver5 = %#x", (unsigned int)pver5);

執行這個函式,輸出如下:

g_pdrvadaptdm = 0x65daea0

ver5 = 0x65daeb0

經過一次自動型別轉換後的指標值,居然和原來的指標值不一樣!

這下明白問題出在哪兒了,恰恰就是因為上層在呼叫時用的是cdrvadaptdm物件的位址,而不是經過轉換後的指標,導致了呼叫出錯。

其實,對於多重繼承的子類,由於它必須要實現多個虛函式表,所以它的資料結構和多個父類的關係如下:

在編譯時,編譯器會根據父類指標的不同型別,對子類指標的值進行轉換。

這個時候的型別轉換就不僅僅是語義轉換這麼簡單的事了,還會實實在在的改變指標的值。

那麼上層呼叫時使用的指標為什麼沒有經過恰當的轉換呢?我找到上層獲取指標的**:

void* cdrvadpcomm::querydrvadp(const dword& dwclassid)

原來上層獲取到的是個void*指標!難怪沒辦法進行恰當的型別轉換。即使把cdrvadaptdm指標轉換成void*以後,再強制轉換成idmial_ver5指標,結果也不正確。因為一旦轉成void*,指標的型別資訊就全部丟掉了,只剩下乙個乾巴巴的值。

由於現有的**架構把所有的物件指標都儲存在void指標陣列裡面,我只好在一開始將轉換好的指標也加入到void指標陣列裡去,然後在上層查詢idmial_ver5的指標時,返回這個新的指標。

問題是解決了,但讓我感到不解的是:為啥非要用void指標陣列來儲存這些物件?它們又不是沒有共同基類。只要用乙個公有基類指標來訪問這些物件,再在需要派生類型別時使用dynamic_cast轉換,就可以讓編譯器的rtti特性來為我們構造防護網,比起void*轉換要安全得多。

比如,像下面這樣的**就是安全的**:

idmial_ver5* pver5 = querydrvadp(classid_drvadp_dm_ver5);

cdrvadaptdm* pdrvadaptdm = dynamic_cast(pver5);

if (pdrvadaptdm)

dynamic_cast允許把乙個基類的指標轉換成其派生類的指標(反過來當然更沒問題),前提是物件的實際型別符合派生類型別。假如實際型別不符合,轉換後的指標將會是null。dynamic_cast型別轉換是優雅的c++**唯一推薦使用的型別轉換方式。

萬惡的英語

entity en ti ty ent t n.實體 本質 存在 attribute at trib ute tr bju t n.屬性 標誌,象徵 特質,特性 定語 v.歸於,屬於 perspective per spec tive p r spekt v p s n.遠景,透視,看法 take ...

萬惡的英語

entity en ti ty ent t n.實體 本質 存在 attribute at trib ute tr bju t n.屬性 標誌,象徵 特質,特性 定語 v.歸於,屬於 perspective per spec tive p r spekt v p s n.遠景,透視,看法 take ...

萬惡的中介

中介者模式 鬥地主 using system.collections.generic region 主程式 public class 鬥地主 endregion 乙個牌局 中介者 public class mediator 倍率 public int multiple 加入 public bool ...