最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊

Godot Source Code Note 3

2023-06-27 15:31 作者:中專人  | 我要投稿

非靜態(tài)成員函數(shù)指針類型擦除

在Godot源碼中,Object類中聲明并定義了一個(gè)名為_bind_methods的函數(shù):

該函數(shù)通過調(diào)用ClassDB類中的靜態(tài)方法bind_method()完成Object類中成員函數(shù)的注冊。

由于Godot中關(guān)于Scene的類均直接或間接繼承自O(shè)bject類,因此類似Node3D、Area3D的類就可以覆寫(注意:不是虛函數(shù)的重寫)父類中bind_method()方法完成自身類中成員函數(shù)的注冊。

class_db.h文件中對(duì)ClassDB::bind_method()函數(shù)的定義:

args數(shù)組存儲(chǔ)函數(shù)的默認(rèn)實(shí)參,argptrs數(shù)組則存儲(chǔ)args數(shù)組中對(duì)應(yīng)函數(shù)默認(rèn)實(shí)參的地址。接下來通過create_method_bind函數(shù),將成員函數(shù)指針包裝成一個(gè)MethodBind派生類對(duì)象,并返回MethodBind基類指針。

create_method_bind函數(shù)的四個(gè)重載版本定義在method_bind.h文件中:

在此以第一種重載版本為例,其余不再贅述,其實(shí)現(xiàn)如下:

這里主要討論無TYPED_METHOD_BIND宏的MethodBindT類構(gòu)造方法(MethodBindT類繼承自MethodBind類),這是簡化了的MethodBindT類定義:

可以看出MethodBindT類有一個(gè)void (MB_T::*)(P...)類型的成員變量method,而其構(gòu)造函數(shù)接受一個(gè)相同類型的變量p_method并將其賦值給method。

從create_method_bind函數(shù)中也可以看到,在MethodBindT構(gòu)造函數(shù)中,reinterpret_cast<void (MB_T::*)(P...)>(p_method)將p_method重新解釋為void (MB_T::*)(P...)類型的成員函數(shù)指針。

在代碼中找到了關(guān)于MB_T的部分:

也就是說,MB_T只是__UnexistingClass的別名,但__UnexistingClass只有聲明沒有定義!

為什么要這么做?

為了弄清這個(gè)問題,不得不簡要了解一下C++類中的內(nèi)存布局。

概念上來說,從C++類中實(shí)例化出的每個(gè)對(duì)象,都獨(dú)立擁有非靜態(tài)的成員變量數(shù)據(jù)與成員函數(shù)代碼。

單獨(dú)為每個(gè)對(duì)象保存成員函數(shù)代碼段會(huì)造成大量內(nèi)存浪費(fèi),因此成員函數(shù)代碼段其實(shí)是僅有一份且共享地址的。

不難猜測,&ClassName::FunctionName取得的結(jié)構(gòu)體一定包含成員函數(shù)地址(注意:為什么是結(jié)構(gòu)體,而不僅僅是函數(shù)地址,后面會(huì)提到)。

眾所周知,非靜態(tài)成員函數(shù)的調(diào)用必須要在對(duì)象中,那么僅僅知道成員函數(shù)地址還不行,因此編譯器會(huì)在調(diào)用成員函數(shù)時(shí)傳入this指針以代表當(dāng)前對(duì)象。這樣,就可以完成對(duì)象對(duì)成員函數(shù)的調(diào)用。

這個(gè)所謂的成員函數(shù)指針到底是什么?

首先根據(jù)之前的推測,成員函數(shù)指針中一定包含了對(duì)應(yīng)函數(shù)代碼段地址。

那么為什么成員函數(shù)指針無法轉(zhuǎn)換為一個(gè)函數(shù)地址呢?

考慮一下多繼承的情況,比如D類同時(shí)繼承了A類和B類,那么在調(diào)用父類(A類和B類)成員函數(shù)時(shí),需要根據(jù)父類(A類和B類)在子類(D類)中的內(nèi)存布局來調(diào)整this指針并傳入對(duì)應(yīng)父類(A類和B類)成員函數(shù)中。

那么很容易想到,成員函數(shù)指針包含的另一個(gè)數(shù)據(jù)肯定與類中內(nèi)存布局有關(guān),即父類在子類中的偏移量,而這就可滿足計(jì)算得到父類this指針的要求。

總結(jié)一下,成員函數(shù)指針應(yīng)該是一個(gè)結(jié)構(gòu)體,其中包含了成員函數(shù)代碼段地址與類的內(nèi)存偏移量。

&ClassName::FunctionName是對(duì)象無關(guān)的,因此不經(jīng)過對(duì)象也能直接取到成員函數(shù)指針也就不奇怪了。

當(dāng)然了,以上僅為一種可能的實(shí)現(xiàn)方式,具體實(shí)現(xiàn)根據(jù)平臺(tái)不同存在差異。

解釋清楚成員函數(shù)指針,reinterpret_cast<void (MB_T::*)(P...)>(p_method)也就很好理解了。

任意類型的成員函數(shù)指針p_method,可以直接解釋為結(jié)構(gòu)相同的__UnexistingClass::*類型,并賦值給method變量。

由此便完成了對(duì)成員函數(shù)指針的類型擦除。

從MethodBindT的構(gòu)造函數(shù)中返回,就得到了成員函數(shù)指針的MethodBind包裝類型的指針。

接下來將類的名稱存儲(chǔ)在MethodBind對(duì)象的成員變量中,將指針從create_method_bind中返回。

標(biāo)記返回值類型是否為Object指針后,調(diào)用bind_methodfi()函數(shù)完成非靜態(tài)成員函數(shù)注冊。

最后再看一下成員函數(shù)指針的調(diào)用方法:

傳入具體對(duì)象完成成員函數(shù)的調(diào)用,語法為:

最后再附一個(gè)簡化后的例子:

但在C++11后可以使用std::function庫函數(shù)完成對(duì)函數(shù)的包裝:


如侵刪。
歡迎評(píng)論指正。

Godot Source Code Note 3的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國家法律
赣榆县| 巨野县| 克山县| 乐平市| 晋宁县| 五寨县| 勐海县| 灵山县| 梓潼县| 外汇| 许昌县| 安徽省| 铅山县| 浮山县| 盐源县| 麦盖提县| 辽宁省| 五原县| 根河市| 南平市| 东辽县| 邳州市| 开鲁县| 酉阳| 高淳县| 左贡县| 杭锦旗| 永丰县| 黑水县| 枣阳市| 吉林省| 台北县| 上林县| 综艺| 同江市| 大庆市| 小金县| 伊宁县| 莱州市| 万全县| 寿光市|