post构造函数初始化

时间:2013-04-01 10:56:37

标签: c++

我有一组派生自公共基础ApiObject的对象。我需要能够在一个单独的数据结构中注册所有ApiObjects,但我需要有一个创建对象的实际地址,而不是基类(我使用多重继承)。

我不能把代码放在ApiObject构造函数中注册一个对象,因为它不知道派生对象的地址;也不能把它放在派生类的构造函数中,因为我们无法知道我们是否实际构造另一个派生类(例如,如果类B是从A继承的,并且两者都可以构造)。

所以我看到的唯一选择是每次创建对象时显式调用注册函数,如

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

然而,这似乎不是一个非常好的解决方案,因为我必须记住每次调用此函数。

我想我应该提供更多背景来解释我为什么要这样做。对象是通过重载的new运算符创建的,它需要对象知道它在(Lua状态)中创建的上下文。 E.g。

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

目前它以一种不太优雅的方式完成 - new运算符在对象之前分配额外的字节并将L指针存储在那里,以及一些额外的数据来描述对象类型。然后,基类通过init函数接收指向此“元数据”的指针 否则,首先想到的是虚函数,但它们不能从构造函数中调用,所以我必须注册基ApiObject指针,但只能在稍后调用虚函数,而且我不确定它比我目前的实施更漂亮。

4 个答案:

答案 0 :(得分:2)

RegisterObject所需的类型是什么?如果它需要一个 Base*,然后您可以从Base的构造函数中调用它, 无论最终的层次结构如何。如果需要其他类型, 那么你想从该类型的构造函数中调用它;您 not 想要从Base派生的所有类中调用它, 但只适用于那些从任何类型派生的人。

如果RegisterObject需要Base*,您就可以从中调用Base* 函数在派生类中,首先发生的是 您传递它的指针将转换为RegisterObjectBase永远不会收到指向派生对象的指针, 仅限于派生对象中的{{1}}。

答案 1 :(得分: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()指针是正确的,但对象尚未初始化(在父构造函数中访问它)

答案 2 :(得分: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;
}

答案 3 :(得分:0)

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

完全创建所有对象后,可以通过虚函数安全地使用指针地址,也可以动态地将其转换为派生类。