2013-04-01 180 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

您可以从基础构造函数调用注册函数。只需使基础析构函数为虚拟。地址和派生类的地址相同。在整个对象创建之前,请不要使用指针地址。

一旦完全创建了所有的对象,指针地址就可以通过虚拟函数安全地使用或者动态地转换为派生类。