好的,所以,我的想法是我有一个“组件”的地图,它继承自componentBase,并且键入一个对派生最多的*唯一的ID。
只是,我想不出一个让它发挥作用的好方法。我尝试使用构造函数,但这不起作用(也许我做错了)。任何虚拟等继承技巧的问题在于用户必须在底部篡改它们,这可能会被遗忘并使其更少......干净。
*正确的短语?如果 - >是继承; foo来源最多:foo-> foo1-> foo2-> componentBase
以下是一些显示问题的代码,以及为什么CRTP无法删除它: (不,这不是合法的代码,但我试图让我的想法失望)
#include<map>
class componentBase
{ public: virtual static char idFunction() = 0; };
template <class T>
class component
: public virtual componentBase
{
public:
static char idFunction(){ return reinterpret_cast<char>(&idFunction); }
};
class intermediateDerivations1
: public virtual component<intermediateDerivations1>
{
};
class intermediateDerivations2
: public virtual component<intermediateDerivations2>
{ };
class derived1
: public intermediateDerivations1
{ };
class derived2
: public intermediateDerivations1
{ };
//How the unique ID gets used (more or less)
std::map<char, componentBase*> TheMap;
template<class T>
void addToMap(componentBase * c)
{
TheMap[T::idFunction()] = c;
}
template<class T>
T * getFromMap()
{
return TheMap[T::idFunction()];
}
int main()
{
//In each case, the key needs to be different.
//For these, the CRTP should do it:
getFromMap<intermediateDerivations1>();
getFromMap<intermediateDerivations2>();
//But not for these.
getFromMap<derived1>();
getFromMap<derived2>();
return 0;
}
或多或少,我需要一些始终存在的东西,无论用户做什么,并且具有可派生的值,这对于派生程度最高的类是唯一的。
另外,我意识到这不是最好问的问题,我实际上有一些意想不到的难以用言语包围我的头脑,所以在需要澄清的时候提出问题。
编辑:
使用Beta的短语; 类 derived2有一个ID号,在从ComponentBase派生的所有类中都是唯一的,并且不会从中派生其他类 - 除了应该没有我们在处理实例时的用例我们不知道最衍生的类型。也就是说,我们永远不应该处理实际上指向``foo`的foo1*
。
任何时候我需要访问此ID,我都有关于派生程度最高的类的类型信息;通过addComponent,getComponent和removeComponent的模板化特性。
嗯,换句话说;当我知道类型时,我需要将“转换”类型转换为唯一的数字,这样当我不具有类型信息时,我可以稍后区分两件事。答案 0 :(得分:0)
我不明白您在reinterpret_cast
中使用class component
的原因。
就拥有唯一ID而言,您应该有某种过程来验证任何派生实例都不使用该ID。
另一方面,每个类都应实现静态 clone
或create
方法。 工厂的版本为map
。函数指针指向特定类“create
或clone
方法。由于在编译期间无法将std::map
创建为const静态实体,因此我通常使用常量静态数组来保存ID和函数指针。如果数组较小,则性能与map
无关。
示例:
class Base
{;};
// Declare a synonym for a pointer to the creation function.
typedef Base * (*P_Creation_Function)(unsigned int id);
struct Creation_Entry
{
unsigned int class_id;
P_Creation_Function p_creator;
};
class Child1 : public Base
{
public:
static Base * create(unsigned int id);
};
Creation_Entry creation_table[] =
{
{1, Child1::create},
};
static const unsigned int NUM_CREATORS =
sizeof(creation_table) / sizeof(creation_table[0]);
// Process 1: search table for ID
for (unsigned int i = 0; i < NUM_CREATORS; ++i)
{
if (creation_table[i].class_id == new_id)
{
return (*creation_table[i].p_creator)(new_id);
}
}
// Process 2: Execute each creation function in the table.
// Creation functions will return NULL if the ID is not a match
Base * p_new_object;
for (unsigned int j = 0; j < NUM_CREATORS; ++j)
{
p_new_object = (*creation_table[j].p_creator)(new_id);
if (p_new_object)
{
return p_new_object;
}
}
对于小型项目,与其他瓶颈(例如磁盘i / o)相比,创建函数返回NULL的开销并不重要。第二个过程不要求工厂知道类ID;类ID仍然封装在类中。
我已经使用了这两个流程并根据我的心情和项目规模来实现它们。 : - )
答案 1 :(得分:0)
您可以使用typeid运算符。
如果您有ComponentBase *组件,那么
typeid(*component)
将返回type_info&amp;唯一标识组件指针指向的对象类的对象。 (如果组件指向Derived对象,那么这将返回属于Derived类的type_info对象。请注意,虽然typeid(组件)将返回type_info&amp;表示类型 ComponentBase *,所以取消引用指针很重要。)
然后你可以使用例如。此type_info对象的地址,或type_info :: name()的结果作为地图的键。