由可通过基类访问的最派生类定义的唯一 ID
Posted
技术标签:
【中文标题】由可通过基类访问的最派生类定义的唯一 ID【英文标题】:Unique ID Defined by Most-Derived Class accessible through Base Class 【发布时间】:2010-03-17 22:58:56 【问题描述】:好的,所以,我的想法是我有一个“组件”映射,它继承自 componentBase,并以最衍生的唯一 ID 为键*。
只是,我想不出一个好的方法来让它工作。我用构造函数尝试了它,但这不起作用(也许我做错了)。任何虚拟等继承技巧的问题是用户必须在底部隐含它们,这可能会被遗忘并使其不那么……干净。
*正确的短语? if -> 是继承; 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 的措辞; class derived2 有一个 ID 号,在所有从 ComponentBase 派生的类中是唯一的,并且没有其他类派生自该 ID 号 - 除了不应该有我们正在处理实例的用例我们不知道派生最多的类型。也就是说,我们永远不必处理实际上指向“foo”的foo1*
。
任何时候我需要访问这个 ID,我都有关于最派生类的类型信息;通过 addComponent、getComponent 和 removeComponent 的模板化特性。
嗯,换一种说法;我需要在知道类型的情况下将类型“转换”为唯一数字,以便以后在我没有类型信息时区分两件事。
【问题讨论】:
你以前也问过类似的问题。这有什么不同? 你的意思是,derived2 的每个实例都有一个 ID 号,在 ComponentBase 的所有实例中是唯一的吗?或者派生类有一个 ID 号,在从 ComponentBase 派生的所有类中是唯一的?或者在所有从 ComponentBase 派生的类中并且没有派生其他类? @Tronic:之前的问题没有涉及继承;因此,可以轻松保证 idFunction() 满足限制,因为不依赖用户程序员来实现它。 【参考方案1】:我不明白你为什么在class component
中使用reinterpret_cast
。
就拥有唯一 ID 而言,您应该有某种流程来验证该 ID 未被任何派生实例使用。
另一方面,每个类都应该实现一个静态 clone
或create
方法。 factory 将有一个 map
of 。函数指针指向特定类的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;
对于小型项目,创建函数返回 NULL 的开销与其他瓶颈(例如磁盘 i/o)相比并不显着。第二个过程不需要工厂知道类ID;类 ID 仍然封装在类中。
我已经使用了这两个流程,并根据我的心情和项目规模来实施它们。 :-)
【讨论】:
我并没有完全理解你所说的,但我认为你遗漏了一些东西。首先,我不知道你的new_id 是什么意思。其次,看起来也许您正在为每个实例设置唯一的 ID,这不是问题。第三,您似乎需要用户代码来实现给定的功能,避免该功能也是问题的一部分。【参考方案2】:您可以使用 typeid 运算符。
如果你有一个 ComponentBase* 组件,那么
typeid(*component)
将返回一个 type_info& 对象,该对象唯一标识组件指针指向的对象的类。 (如果组件指向 Derived 对象,那么这将返回属于 Derived 类的 type_info 对象。请注意,尽管 typeid(component) 将返回表示类型 ComponentBase* 的 type_info&,因此取消引用指针很重要。)
然后你可以使用例如。此 type_info 对象的地址,或 type_info::name() 的结果作为地图的键。
【讨论】:
以上是关于由可通过基类访问的最派生类定义的唯一 ID的主要内容,如果未能解决你的问题,请参考以下文章