我正在尝试在C ++中实现某种机制,从而为从公共基类派生的所有类分配一个唯一的“类ID”。例如:
class BaseClass
{
//...
public: unsigned int GetID( void );
//...
};
class DerivedClass : public BaseClass
{
}
类DerivedClass和BaseClass的所有其他子项应该能够返回唯一标识符,而不需要向DerivedClass添加任何额外的代码......但是,C ++对我来说相当困难。任何想法都将不胜感激。
提前致谢! ---丹
答案 0 :(得分:2)
您并不表示您熟悉typeid
和dynamic_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 );
};