2010-11-16 37 views
1

我需要修改一個開源項目來防止重用代碼(更有效的方法是創建一個GetGameRulesPtr()函數,而不是繼續引擎來檢索它。問題是,它存儲爲void ** g_pGameRules。我從來沒有真正掌握指針的指針的概念,我有點困惑。如何爲雙指針創建一個getter函數?

我創建一個GetGameRules()函數來檢索這個指針,但我不知道如果我的getter函數應該是void * ret鍵入然後返回* g_pGameRules,或者我應該怎麼去做這件事,其實我現在正在刷我的指針用法,但是想找出正確的方法來學習

這裏是代碼58- 89是檢索g_pGame的SDK函數規則遊戲引擎的指針。其他功能是我添加getter函數。

// extension.cpp 

class SDKTools_API : public ISDKTools 
{ 
public: 
    virtual const char *GetInterfaceName() 
    { 
     return SMINTERFACE_SDKTOOLS_NAME; 
    } 

    virtual unsigned int GetInterfaceVersion() 
    { 
     return SMINTERFACE_SDKTOOLS_VERSION; 
    } 

    virtual IServer *GetIServer() 
    { 
     return iserver; 
    } 

    virtual void *GetGameRules() 
    { 
     return *g_pGameRules; 
    } 
} g_SDKTools_API; 

// extension.h 

namespace SourceMod 
{ 
    /** 
    * @brief SDKTools API. 
    */ 
    class ISDKTools : public SMInterface 
    { 
    public: 
     virtual const char *GetInterfaceName() = 0; 
     virtual unsigned int GetInterfaceVersion() = 0; 
    public: 
     /** 
     * @brief Returns a pointer to IServer if one was found. 
     * 
     * @return   IServer pointer, or NULL if SDKTools was unable to find one. 
     */ 
     virtual IServer* GetIServer() = 0; 

     /** 
     * @brief Returns a pointer to GameRules if one was found. 
     * 
     * @return   GameRules pointer, or NULL if SDKTools was unable to find one. 
     */ 
     virtual void* GetGameRules() = 0; 
    }; 
} 

// vglobals.cpp 

void **g_pGameRules = NULL; 
void *g_EntList = NULL; 


void InitializeValveGlobals() 
{ 
    g_EntList = gamehelpers->GetGlobalEntityList(); 

    char *addr; 

#ifdef PLATFORM_WINDOWS 
    /* g_pGameRules */ 
    if (!g_pGameConf->GetMemSig("CreateGameRulesObject", (void **)&addr) || !addr) 
    { 
     return; 
    } 

    int offset; 
    if (!g_pGameConf->GetOffset("g_pGameRules", &offset) || !offset) 
    { 
     return; 
    } 
    g_pGameRules = *reinterpret_cast<void ***>(addr + offset); 
#elif defined PLATFORM_LINUX || defined PLATFORM_APPLE 
    /* g_pGameRules */ 
    if (!g_pGameConf->GetMemSig("g_pGameRules", (void **)&addr) || !addr) 
    { 
     return; 
    } 
    g_pGameRules = reinterpret_cast<void **>(addr); 
#endif 
} 
+1

爲什麼不把代碼作爲問題的一部分包含進來,以便無論當天的貼紙消失,代碼都會保留爲其他人發現此問題的記錄? – Flexo 2010-11-16 00:50:31

+0

對不起,我想我選擇了這個選項,以便ampaste永遠不會刪除我的帖子,但它看起來像我點了一個月。 – 2010-11-16 00:57:12

回答

1

你要執行的代碼中返回一個void*,並做鑄造回相應SomeType**。這是因爲void**有奇怪的語義(我現在無法在Google上找到)。它還告訴用戶比他們真正需要更多的信息。首先使用void*的要點是避免向用戶提供他們不需要的信息。

如果這是一個選項,我個人建議完全避免void*,並簡單地爲他們提供一個不透明的引用類型來調用你的API。一種方法是定義一個假結構,如struct GameObjectRef {};,並將用戶傳回GameObjectRef*,從系統實際使用的任何指針開始。這允許用戶編寫強類型的代碼,因此它們不會意外地向您的函數提供錯誤的指針類型,因爲它們可以使用void*

如何指針(和指針到指針)工作:

想象一下,你問我你姑姑住在哪裏。然後,我遞給你一張帶有地址的紙張。那張紙是指向房子的指針。

現在,拿着那張紙的地址,用你的數碼相機拍下它的照片,並將圖像放到你的個人wiki網站上。

現在,如果你的妹妹打電話,要求你的阿姨的地址,只要告訴她在你的維基上查看它。如果她要求URL,請寫在一張紙上給她。這第二張紙是指向房屋指針的指針。

你可以看到一個地址與真實的東西不一樣。僅僅因爲有人有你的網站地址並不意味着他們知道你的阿姨的地址。只因爲他們有你阿姨的地址並不意味着他們敲門。指向對象的指針也是如此。

您還可以看到如何製作地址(指針)的副本,但是不會製作底層對象的副本。當你拍下你姑姑的地址的照片時,你的阿姨沒有得到一個閃亮的新房子。

你可以看到如何解引用指針會導致你回到原始對象。如果你去維基站點,你會得到你的阿姨的地址。如果你開車到那個地址,你可以在她家門口留下一個包裹。

請注意,這些並不是完美的隱喻,但它們足夠接近以至於具有一定的描述性。真正的指針指針比這些例子要乾淨得多。它們只描述了兩件事 - 最終對象的類型(如GameObject)和間接級別數(例如,GameObject** - 兩級)。

0

,我認爲它不是一個雙指針,而是一個指針的指針,是的,如果你想獲得無效*您必須返回* g_pGameRules。

想的是,指針就像水平。您必須顯示您想要獲得的級別。

+0

這很有道理,謝謝。問題是,如果我使rettype void *並返回* g_pGameRules,是否會返回與** g_pGameRules不同的東西? – 2010-11-16 00:56:38

+0

是的。它將返回指向g_pGameRules的指針。但它的地址存儲在void ** g_pGameRules。像「指針 - >指針 - >值」。當您使用在堆上分配其組件的類時,您可以看到這一點。示例「SomeClassInst-> AnotherCLassInst-> ValueYouWantToChange」 – DmitryM 2010-11-16 00:58:52

0

如果您想讓指針更改(例如,如果您用完,則指向更大的內存塊),但指向指針的指針非常有用,但保留對該項目的任何移動位置的通用引用。

如果你不打算重新分配或移動指向的塊,那麼dereferencinig就像你在你的getter中有很好的一樣。我沒有看過你正在使用的庫,但需要考慮的一件事是,當你得到一個實例時,它可能有引用計數,以確保在你得到指針後對象沒有被改變。

所以,我建議你看看庫是否有任何「工廠」功能或「實例」創建功能和使用這些。

-Dan8080