C++ design with static methods
我想用静态方法定义为X类:
1 2 3 4 5 | class X { static string get_type () {return"X";} //other virtual methods } |
我想强制从x继承的类重新定义get_type()方法并返回不同于"x"的字符串(如果他们现在重新定义get_类型,我很高兴)。
我该怎么做?我知道我不能有虚拟静态方法。
编辑:问题不是关于类型_ID,而是关于一个静态方法,应该被覆盖。例如
1 2 3 | class X { static int getid() {return 1;} } |
1 2 3 4 5 6 7 8 | template<int id> class X { public: static int getid() { return id; } }; class Y : public X<2> { }; |
您没有重写该方法,但是您已经强制每个子类提供一个ID。警告:我没有尝试过这个方法,可能有一些微妙的原因导致它不能工作。
如果我没有弄错,要调用静态方法,您必须通过指定类的确切名称来调用该方法,例如
但是,我不明白为什么不应该强制每个有趣的类(继承或不继承,因为"编译时多态性"并不关心)为这个功能提供模板。在以下情况下,您必须专门化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #include <string> struct X {}; struct Derived: X {}; template <class T> std::string get_type() { static_assert(sizeof(T) == 0,"get_type not specialized for given type"); return std::string(); } template <> std::string get_type<X>() { return"X"; } int main() { get_type<X>(); get_type<Derived>(); //error } |
(EDOCX1)4是C++0x,否则使用您最喜欢的实现,例如EDCOX1(5)。如果您对专门化函数感到不好,请改为专门化一个结构。如果你想强制一个错误,如果有人不小心试图将它专门化为不是从x派生的类型,那么这也可以用
我想说你知道原因,但为了以防万一,这里有一个很好的解释:
http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=/com.ibm.xlcpp8l.doc/language/ref/cpl139.htm(主题=/com.ibm.xlcpp8l.doc/language/ref/cpl139.htm)
看来你得设计出一种解决办法。也许是一个包装单例的虚拟函数?
很抱歉恢复了这条线,但我也刚刚遇到了这个道德危机。这是一个非常大胆和可能愚蠢的说法,但我完全不同意大多数人所说的关于
人们通常使用静态类和/或成员来表达事实-如果实例相关,那么对于所有实例都是这样,或者对于静态类来说,仅仅是关于世界的事实。假设你在模拟一门哲学课。你可以把
但是,我完全同意那些以
我能想到的解决这个问题的最好办法是把
使用delphi,它支持类上的虚拟静态成员。>
您提到了一些关于确保子类型为您的函数生成唯一值的地方。正如其他人所说,这在编译时是不可能的[至少,没有使用模板,这可能是或可能是不可接受的]。但是如果你把它延迟到运行时,你可能会得到类似的东西。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 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之前会抛出异常。如果愿意的话,可以将注册转移到构造函数中,并接受注册检查的每个实例开销。
为了简单起见,我选择了一个无序向量;我不确定
我没有试图防止初始化错误的静态顺序。如文所述,这将在某个时候失败。
最后,不,它不是静态的,但是"静态的"和"虚拟的"无论如何都没有真正意义。如果您没有要操作的类型实例,那么如何知道要选择哪个覆盖方法?对于模板,有一些情况下您可能会合法地希望调用没有实际对象的静态方法,但这不太常见。
*编辑:另外,我不确定它如何与动态链接库等交互。我怀疑RTTI在这些情况下是不可靠的,所以很明显这也是不可靠的。
干得好
1 2 3 4 5 6 7 8 9 | class X { static string get_type() {return"X"; } }; class Y : public X { static string get_type() {return"Y"; } }; |
上面的代码完全按照您的要求执行:派生类重新定义
你不能这样做有很多原因。您不能在x中定义函数,并让它是纯虚拟的。您根本不能拥有虚拟静态函数。
为什么它们必须是静态的?
长话短说,你做不到。要求派生类重写基类函数的唯一方法是使其成为纯虚拟(不能是静态的)。
不要这样做,用