您提到了一些关于保证子类型为您的函数产生唯一值的地方。正如其他人所说,这在编译时是不可能的[至少,不使用模板,这可能是也可能是不可接受的]。但是,如果您将其延迟到运行时,您可能会执行类似的操作。
class Base {
static std::vector<std::pair<const std::type_info*, int> > datas;
typedef std::vector<std::pair<const std::type_info*, int> >::iterator iterator;
public:
virtual ~Base() { }
int Data() const {
const std::type_info& info = typeid(*this);
for(iterator i = datas.begin(); i != datas.end(); ++i)
if(*(i->first) == info) return i->second;
throw "Unregistered Type";
}
static bool RegisterClass(const Base& p, int data) {
const std::type_info& info = typeid(p);
for(iterator i = datas.begin(); i != datas.end(); ++i) {
if(i->second == data) {
if(*(i->first) != info) throw "Duplicate Data";
return true;
}
if(*(i->first) == info) throw "Reregistering";
}
datas.push_back(std::make_pair(&info, data));
return true;
}
};
std::vector<std::pair<const std::type_info*, int> > Base::datas;
class Derived : public Base { };
const DerivedRegisterFlag = Base::RegisterClass(Derived(), 10);
class OtherDerived : public Base { };
const OtherDerivedRegisterFlag = Base::RegisterClass(OtherDerived(), 10); //exception
警告:这是完全未经测试的。如果你这样做,在进入 main 之前会抛出异常。您可以将注册移到构造函数中,如果愿意,可以接受注册检查的每个实例开销。
为了简单起见,我选择了一个无序向量;我不确定type_info::before 是否提供了必要的语义来用作地图的谓词,并且大概你不会有这么多派生类,以至于线性搜索无论如何都会有问题。我存储了一个指针,因为您不能直接复制 type_info 对象。这主要是安全的,因为typeid 返回的对象的生命周期是整个程序。程序关闭时可能会出现问题,我不确定。
我没有尝试防止初始化错误的静态顺序。正如所写,这将在某些时候失败。
最后,不,它不是静态的,但无论如何,“静态”和“虚拟”并没有真正的意义。如果您没有要操作的类型的实例,那么您如何知道选择哪个覆盖的方法?在某些情况下,您可能希望在没有实际对象的情况下合理地调用静态方法,但这并不常见。
*edit:另外,我不确定它如何与动态链接库等交互。我怀疑 RTTI 在这些情况下不可靠,所以显然这同样不可靠。