有可能!
但究竟有什么可能,让我们缩小范围。人们经常想要某种“静态虚函数”,因为需要重复代码才能通过静态调用“SomeDerivedClass::myfunction()”和多态调用“base_class_pointer->myfunction()”调用相同的函数。允许此类功能的“合法”方法是重复功能定义:
class Object
{
public:
static string getTypeInformationStatic() { return "base class";}
virtual string getTypeInformation() { return getTypeInformationStatic(); }
};
class Foo: public Object
{
public:
static string getTypeInformationStatic() { return "derived class";}
virtual string getTypeInformation() { return getTypeInformationStatic(); }
};
如果基类有大量的静态函数,而派生类必须重写它们中的每一个,而忘记为虚函数提供重复定义怎么办。是的,我们会在 runtime 期间遇到一些难以追踪的奇怪错误。因为重复代码是一件坏事。下面尝试解决这个问题(我想提前告诉你它是完全类型安全的,并且不包含任何像 typeid 或 dynamic_cast 的黑魔法:)
因此,我们只想为每个派生类提供一个 getTypeInformation() 定义,显然它必须是 static 函数的定义,因为不可能调用“SomeDerivedClass: :getTypeInformation()" 如果 getTypeInformation() 是虚拟的。我们如何通过指向基类的指针调用派生类的静态函数?使用 vtable 是不可能的,因为 vtable 只存储指向虚函数的指针,而且由于我们决定不使用虚函数,所以我们不能为了我们的利益而修改 vtable。然后,为了能够通过指向基类的指针访问派生类的静态函数,我们必须以某种方式将对象的类型存储在其基类中。一种方法是使用“奇怪的重复模板模式”将基类模板化,但在这里不合适,我们将使用一种称为“类型擦除”的技术:
class TypeKeeper
{
public:
virtual string getTypeInformation() = 0;
};
template<class T>
class TypeKeeperImpl: public TypeKeeper
{
public:
virtual string getTypeInformation() { return T::getTypeInformationStatic(); }
};
现在我们可以使用变量“keeper”将对象的类型存储在基类“Object”中:
class Object
{
public:
Object(){}
boost::scoped_ptr<TypeKeeper> keeper;
//not virtual
string getTypeInformation() const
{ return keeper? keeper->getTypeInformation(): string("base class"); }
};
在派生类中,keeper必须在构造时初始化:
class Foo: public Object
{
public:
Foo() { keeper.reset(new TypeKeeperImpl<Foo>()); }
//note the name of the function
static string getTypeInformationStatic()
{ return "class for proving static virtual functions concept"; }
};
让我们添加语法糖:
template<class T>
void override_static_functions(T* t)
{ t->keeper.reset(new TypeKeeperImpl<T>()); }
#define OVERRIDE_STATIC_FUNCTIONS override_static_functions(this)
现在后代的声明如下:
class Foo: public Object
{
public:
Foo() { OVERRIDE_STATIC_FUNCTIONS; }
static string getTypeInformationStatic()
{ return "class for proving static virtual functions concept"; }
};
class Bar: public Foo
{
public:
Bar() { OVERRIDE_STATIC_FUNCTIONS; }
static string getTypeInformationStatic()
{ return "another class for the same reason"; }
};
用法:
Object* obj = new Foo();
cout << obj->getTypeInformation() << endl; //calls Foo::getTypeInformationStatic()
obj = new Bar();
cout << obj->getTypeInformation() << endl; //calls Bar::getTypeInformationStatic()
Foo* foo = new Bar();
cout << foo->getTypeInformation() << endl; //calls Bar::getTypeInformationStatic()
Foo::getTypeInformation(); //compile-time error
Foo::getTypeInformationStatic(); //calls Foo::getTypeInformationStatic()
Bar::getTypeInformationStatic(); //calls Bar::getTypeInformationStatic()
优点:
- 更少的代码重复(但我们
必须打电话
OVERRIDE_STATIC_FUNCTIONS 在每个
构造函数)
缺点:
- OVERRIDE_STATIC_FUNCTIONS 在每个
构造函数
- 内存和性能
开销
- 复杂性增加
未解决的问题:
1) 静态函数和虚函数有不同的名称
如何解决这里的歧义?
class Foo
{
public:
static void f(bool f=true) { cout << "static";}
virtual void f() { cout << "virtual";}
};
//somewhere
Foo::f(); //calls static f(), no ambiguity
ptr_to_foo->f(); //ambiguity
2) 如何在每个构造函数中隐式调用 OVERRIDE_STATIC_FUNCTIONS?