公共基类的派生类的TypeID

时间:2010-11-26 01:59:16

标签: c++ types typeid

我正在尝试在C ++中实现某种机制,从而为从公共基类派生的所有类分配一个唯一的“类ID”。例如:

class BaseClass  
{  
    //...
    public: unsigned int GetID( void );
    //...
};
class DerivedClass : public BaseClass
{
}

类DerivedClass和BaseClass的所有其他子项应该能够返回唯一标识符,而不需要向DerivedClass添加任何额外的代码......但是,C ++对我来说相当困难。任何想法都将不胜感激。

提前致谢! ---丹

4 个答案:

答案 0 :(得分:2)

您并不表示您熟悉typeiddynamic_cast

他们有机会解决你的问题。

如果没有,请说明原因。

干杯&第h。,

答案 1 :(得分:2)

你应该听听Alf :)这是我的分析:在纯粹的世界中,识别实现威胁虚函数多态,不是必需的,也不应该需要。

在真实编程的肮脏世界中,您可能有一些独特识别的原因,例如将数据封送到磁盘,识别诊断消息,跟踪控制流,累积使用统计信息等。

如果你的想法很纯粹,你的设计就错了。走开,弄清楚为什么你不能要求一个唯一的ID。

如果您的想法被现实所破坏,那么您已经愿意为性能和内存付出代价以满足您的要求,然后通过规范,使用内置语言功能的成本是值得付出的,因为它是几乎是实现提供无创识别服务目标的唯一途径。非侵入性我的意思是你不需要为每个派生类添加任何东西。显然必须添加一些东西,所以如果你不愿意这样做,你别无选择,只能接受编译器为你添加的内容。

这里的主要问题是,如果您使用动态加载的共享库(DLLS),RTTI可能无法按预期工作。这不仅会对typeid造成不利影响,还可以防止捕获您期望被捕获的异常(我被咬过了!)。可能需要注意确保vtable和其他RTTI是唯一创建的。例如,这可能意味着,如果vtables挂钩在析构函数上,则它不是内联的,因为在这种情况下它可能会在多个位置生成,从而破坏唯一性。在没有ISO标准化支持动态加载的情况下,可能需要进行一些黑客攻击。

答案 2 :(得分:1)

正如阿尔夫所说,这不应该是必要的。虽然标识符不是整数,但typeid已经提供了唯一的类标识符。只是为了笑,如果我被允许放松“共同基类”的条件,那么:

inline unsigned int counter() {
    static unsigned int count = 0;
    return ++count;
}

struct BaseClass {
    virtual unsigned int GetID() = 0;
    virtual ~BaseClass() {}
};

template <typename D>
struct IntermediateClass : BaseClass {
    virtual unsigned int GetID() {
        static unsigned int thisid = counter();
        return thisid;
    }
};

// usage
struct Derived : IntermediateClass<Derived> {
    ...
};

如果要在多线程程序中使用,则需要在counter中添加线程安全性。

显然,ID在程序的给定运行中是唯一的。

如果您的继承层次结构很深,并且如果您有许多具有不同类的不同签名的构造函数,则会有点毛茸茸,因为您需要在每个派生类及其直接基类之间插入IntermediateClass。但你可以随时摆脱所有这些:

inline unsigned int counter() {
    static unsigned int count = 0;
    return ++count;
}

struct BaseClass {
    virtual unsigned int GetID() = 0;
    virtual ~BaseClass() {}
};

template <typename D>
unsigned int ThisID(const D *) {
    static unsigned int thisid = counter();
    return thisid;
}

// usage
struct Derived : BaseClass {
    // this single line pasted in each derived class
    virtual unsigned int GetID() { return ThisID(this); }
    ...
};

我猜这里有一个新的语言功能的“机会”:一个虚函数,它在基类中定义为带有一个“typename”模板参数的模板函数,并在每个派生类中使用该函数自动覆盖派生类作为模板参数。虚构的语法,因为虚拟模板函数是非法的:

struct BaseClass {
    template <typename Derived>
    virtual unsigned int GetID() {
        static unsigned int thisid = counter();
        return thisid;
    }
    virtual ~BaseClass() {}
};

基于想要自己重新实施RTTI而难以证明语言功能的合理性,请注意......

答案 3 :(得分:0)

这确实需要修改派生类,但如果对RTTI缺乏信心是避免完全建立的typeid路由的唯一原因,那就是dynamic_cast,那么

这样的事情应该是一个不错的选择。与RTTI的'type_info'相比,它还返回'int'。

class BaseClass{   
    //... 
    public:
       virtual unsigned int GetID( void ); 
    //... 
};

class DerivedClass : public BaseClass{
public: 
   virtual unsigned int GetID( void );
};