有可能的!
但是,到底有什么可能,让我们缩小范围。人们经常想要某种“静态虚拟函数”,因为能够通过静态调用“ 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(); }
};
如果基类具有大量静态函数,而派生类必须重写它们中的每一个,而又忘记为虚拟函数提供重复的定义,该怎么办?是的,我们在运行时会遇到一些奇怪的错误,很难跟踪。导致代码重复是一件坏事。以下尝试解决此问题(并且我想事先告诉您,它完全是类型安全的,并且不包含typeid或dynamic_cast的任何黑魔法:)
因此,我们只想为每个派生类提供一个getTypeInformation()定义,很明显,它必须是 static函数,因为如果getTypeInformation()是虚拟的,则不可能调用“ SomeDerivedClass :: 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?
const
方法中的签名将隐式this
指针标记为常量,并且由于缺少隐式参数而无法应用于静态方法。