由可通过基类访问的最派生类定义的唯一 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 未被任何派生实例使用。

另一方面,每个类都应该实现一个静态 clonecreate 方法。 factory 将有一个 map of 。函数指针指向特定类的createclone 方法。由于在编译期间无法将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的主要内容,如果未能解决你的问题,请参考以下文章

关于C++基类、派生类的引用和指针

向上强制转换和向下强制转换

关于C++基类与派生类

继承和派生

C++中的派生类,可以不定义对象直接调用基类的成员和调用自己的成员函数嘛???

C#编程,关于基类和派生类