2013-04-01 181 views
0

我有一組從對象公共基礎派生的對象,​​。我需要能夠在一個單獨的數據結構中註冊所有ApiObject,但我需要有一個實際的被創建對象的地址,而不是基類(我使用多重繼承)。創建構造函數初始化

我不能把代碼註冊在​​構造函數中的對象,因爲它不知道派生對象的地址;也不能將它放到派生類的構造函數中,因爲我們無法知道我們是否實際構造了另一個派生類(例如,如果類BA繼承,並且都可以構造)。

所以我看到的唯一選擇是顯式調用註冊功能我們每次創建對象時,如

B* b = new B(...); 
RegisterObject(b); 

然而,這似乎並沒有得到很好的解決方案,因爲我有記得每次調用這個函數。

我想我應該給更多的上下文來解釋我爲什麼要這樣做。這些對象是通過一個重載的new運算符創建的,它需要該對象知道它創建的上下文(Lua狀態)。例如。

Foo* object = new(L) Foo(...); 
// Foo is derived from ApiObject, and we want ApiObject to have a reference to L 

目前,它以某種方式unelegant完成 - 新的運營商那裏的對象之前分配額外的字節,並存儲爲L指針,與其他一些數據來描述對象類型一起。基類然後通過init函數接收到一個指向這個'元數據'的指針。否則,首先想到的是虛函數,但它們不能從構造函數中調用,所以我不得不註冊基指針,但只在稍後的時間點調用虛函數,而我我不確定這比我目前的實施更漂亮。

+0

你想對實際地址做什麼? –

+0

@JoachimPileborg「這在派生和基礎對象中都是一樣的」---不,不是真的。 –

+0

@JoachimPileborg這不會是基類和派生類中的相同物理地址。 –

回答

0

您可以添加或刪除您要從CRTP類註冊的每個對象,該類執行註冊,例如,

template<class T> 
struct registarar_t<T> 
{ 
    registarar_t() 
    { 
    register(derived()); 
    } 

    T* derieved() 
    { 
    return static_cast<T*>(this); 
    } 
} 

struct IWantToRegister : registrar_t<IWantToRegister>, ApiObject 
{ 
} 

此外,小心derived()指針是正確的,但對象尚未初始化(在父類的構造訪問它)

+0

從技術上講,'static_cast'是未定義的行爲(雖然我無法想象它失敗)。如果基類是虛擬的(這通常會涉及多重繼承)也是非法的。 –

+0

@JamesKanze爲什麼沒有定義? –

+0

在這種情況下,我可以給出的唯一答案是「因爲 標準是這樣說的」。在沒有虛擬派生的情況下,我無法看出爲什麼它不能平凡地工作。 如果存在虛擬派生,則'static_cast'爲 非法。但§3.8/ 5明確表示它是未定義的 行爲。 –

0

也許kassak的解決方案是更優雅,我沒那麼先進,但我建議是這樣的(註冊shoudl在構造函數中調用,所以你不必每次都寫:

#include <iostream> 
struct ApiObject; 
void registerObj(ApiObject *foo); 

struct ApiObject{ 
    public: 
     ApiObject(std::string n){ 
      name = n; 
      registerObj(this); 
     } 

     std::string name; 
}; 

void registerObj(ApiObject *foo){ 
    std::cout<<"register called on "<<foo->name<<"\n"; 
} 


struct A : public ApiObject{ 
    public: 
     A(std::string n) : ApiObject(n) { 
      std::cout<<"init A\n"; 
     } 
}; 

struct B : public ApiObject{ 
    public: 
    B(std::string n) : ApiObject(n) { 
     std::cout<<"init B\n"; 
    } 
}; 


int main(){ 
    B *b = new B("b obj"); 
    A *a = new A("a obj"); 

    delete b; 
    delete a; 
} 
2

是什麼RegisterObject需要的類型。如果我t取 Base*,那麼無論最終的層次如何,都可以從Base, 的構造函數中調用它。如果它需要其他類型, 那麼你想從該類型的構造函數中調用它;你 做不是想要從Base, 派生的所有類別調用它,但只適用於從它需要的任何類型派生的類。

如果RegisterObject需要Base*,並從在派生類中的 函數調用它,將發生的第一件事就是 ,你傳遞給它的指針將被轉換爲Base*RegisterObject永遠不會在派生對象中接收到派生對象的指針, 僅限於Base

0

您可以從基礎構造函數調用註冊函數。只需使基礎析構函數爲虛擬。地址和派生類的地址相同。在整個對象創建之前,請不要使用指針地址。

一旦完全創建了所有的對象,指針地址就可以通過虛擬函數安全地使用或者動態地轉換爲派生類。