優(yōu)雅的類型轉(zhuǎn)換

??前面我們討論了CUB開源庫中的AutoMsg組件。今天我們再看下其中所實(shí)現(xiàn)的一種優(yōu)雅的類型轉(zhuǎn)換方式DCI Unknow(在此我們不討論其實(shí)現(xiàn)以及原理,而只是探討其中個(gè)人認(rèn)為實(shí)現(xiàn)不好的地方并進(jìn)行修改。需要了解其原理的同學(xué)可以自行查閱源碼)。

    UNKNOWN_INTERFACE(Unknown, 0xFFFFFFFE)
    {
        virtual void* castTo(const ::details::InterfaceId iid) const = 0;
    };

??上述示例定義了最原始轉(zhuǎn)換接口。由于我們不知道最終的轉(zhuǎn)換目標(biāo),所以必須為每一個(gè)角色人為注入不同的特性IID(例如上述的 0xFFFFFFFE)以保證最終轉(zhuǎn)換對象的正確性。人是懶惰的以及具有極強(qiáng)的好奇心。初次使用的人不明原理經(jīng)常會問道“這個(gè)IID我們應(yīng)該怎么定義“(其實(shí)隨意定義就好,只要你能保證其唯一性)。為了結(jié)束這種無休止的追問以及滿足我們懶惰的人性,我們能不能將這個(gè)IID優(yōu)化掉或者對外不可見呢?這個(gè)也就是本文所需要解決的問題。
??首先我們需要解決的問題是“如何產(chǎn)生針對不同角色的特性IID?“我們首先應(yīng)該想到是類的靜態(tài)成員變量,其屬於類本身而不屬於對象,因此也就保證了針對不同類的唯一性。從此我們可以尋找突破口。實(shí)現(xiàn)如下:


typedef unsigned long TypeId;

template <typename T>
class TypeIdHelper {
 public:

  static bool dummy_;
};

template <typename T> bool TypeIdHelper<T>::dummy_ = false;

template <typename T>
TypeId GetTypeId() 
{
  return (TypeId)&(TypeIdHelper<T>::dummy_);
}

??上述我們利用模板編譯期實(shí)例化的特性,創(chuàng)建不同的實(shí)例化對象從而保證靜態(tài)成員變量的唯一性(即地址的唯一性),將其地址直作為IID。上述應(yīng)用過程中要注意靜態(tài)成員不要定義成常量。因?yàn)榫幾g器可能對其進(jìn)行優(yōu)化,從而不能保證唯一性。
??既然已經(jīng)獲取到了唯一的ID,那么后面我們就只需要將其應(yīng)用到其中就OK 了。

    struct Dummy {};

    template <typename T_B1, typename T_B2, typename T_B3>
    struct BaseTraits
    {
        struct Base : T_B1, T_B2, T_B3
        {
                virtual ~Base() {}
        int IID;
        };
    };

    template <typename T_B1, typename T_B2>
    struct BaseTraits<T_B1, T_B2, Dummy>
    {
        struct Base : T_B1, T_B2
        {
                virtual ~Base() {}
        int IID;
        };
    };

    template <typename T_B1>
    struct BaseTraits<T_B1, Dummy, Dummy>
    {
    struct Base:T_B1
    {
        virtual ~Base() {}
        int IID;
    };
    };

    template <>
    struct BaseTraits<Dummy, Dummy, Dummy>
    {
        struct Base
        {
                virtual ~Base() {}
        int IID;
        };
    };

    template <typename T
        ,typename T_B1 = Dummy
             , typename T_B2 = Dummy
             , typename T_B3 = Dummy>
    struct Interface : BaseTraits<T_B1, T_B2, T_B3>::Base
    {
    Interface()
    {
        BaseTraits<T_B1, T_B2, T_B3>::Base::IID = GetTypeId<T>();
    }
        virtual ~Interface() {}
    };

新的宏定義如下

#define DEF_INTERFACE(iface, ...) \
struct iface :Interface<iface,##__VA_ARGS__>

??上述我們只是將原先的IID由Enum常量類型更改為了非常量類型。再沒有任何大得修改,也算比較簡潔了。經(jīng)過上述修改后我們角色的定義變成了下述方式

    UNKNOWN_INTERFACE(Unknown)
    {
        virtual void* castTo(const ::details::InterfaceId iid) const = 0;
    };

可以看到不需要再人為的注入IID了,是不是清爽很多。存在的問題有二:

1.需要提供一個(gè)接口來最外展示IID。
2.些許內(nèi)存開銷。(這個(gè)大家自行尋找吧~~)

最近有點(diǎn)感冒就寫這么多了。有問題歡迎互相討論。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容