0

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

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

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

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

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

4

4 回答 4

2

需要的类型是RegisterObject什么?如果它需要 a Base*,那么您可以从 的构造函数中调用它Base,而不管最终层次结构如何。如果它采用其他类型,那么您想从该类型的构造函数中调用它;您不想从派生自 的所有类中调用它Base,而只想从派生自它所采用的任何类型的类中调用它。

如果RegisterObject需要 a Base*,并且您从派生类中的函数调用它,首先会发生的是您传递给它的指针将转换为 a Base*RegisterObject从不接收指向派生对象的指针,只接收派生对象中的指针Base

于 2013-04-01T11:10:49.653 回答
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()指针是正确的,但对象尚未初始化(在父构造函数中访问它)

于 2013-04-01T11:01:57.747 回答
0

也许kassak的解决方案更优雅,我不是那么先进,但我推荐这样的东西(寄存器应该在构造函数中调用,所以你不必每次都写:

#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;
}
于 2013-04-01T11:10:14.677 回答
0

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

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

于 2013-04-01T11:21:12.520 回答