我有一组派生自公共基础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
指针,但只能在稍后调用虚函数,而且我不确定它比我目前的实施更漂亮。
答案 0 :(得分:2)
RegisterObject
所需的类型是什么?如果它需要一个
Base*
,然后您可以从Base
的构造函数中调用它,
无论最终的层次结构如何。如果需要其他类型,
那么你想从该类型的构造函数中调用它;您
not 想要从Base
派生的所有类中调用它,
但只适用于那些从任何类型派生的人。
如果RegisterObject
需要Base*
,您就可以从中调用Base*
函数在派生类中,首先发生的是
您传递它的指针将转换为RegisterObject
。
Base
永远不会收到指向派生对象的指针,
仅限于派生对象中的{{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)
您可以从基础构造函数中调用注册函数。只需将基础析构函数设为虚拟。基类和派生类的地址相同。只是在创建整个对象之前不要使用指针地址。
完全创建所有对象后,可以通过虚函数安全地使用指针地址,也可以动态地将其转换为派生类。