这段代码:
template <typename T>
struct A
{
T t;
void DoSomething()
{
t.SomeFunction();
}
};
struct B
{
};
A<B> a;
很容易编译,没有任何投诉,只要我从来没有打电话给.DoSomething().
但是,如果我将DoSomething定义为虚函数,我将收到一个编译错误,指出B没有声明SomeFunction.我可以在某种程度上看到它为什么会发生(DoSomething现在应该在vtable中有一个条目),但我不禁觉得它并没有真正的义务.再加上很糟糕.
有没有办法克服这个问题?
编辑2:好的.我希望这次它能够做到:
假设我正在进行侵入式引用计数,因此所有实体都必须从基类Object继承.我怎样才能成为原始类型?我可以定义:
template <typename T>
class Primitive : public Object
{
T value;
public:
Primitive(const T &value=T());
operator T() const;
Primitive<T> &operator =(const T &value);
Primitive<T> &operator +=(const T &value);
Primitive<T> &operator %=(const T &value);
// And so on...
};
所以我可以使用Primitive< int>,Primitive< char> …
但是Primitive< float> ;?怎么样?这似乎是一个问题,因为浮点数没有%=运算符.但实际上,它不是,因为我永远不会在Primitive< float>上调用operator%=.
这是模板的深思熟虑的功能之一.
如果出于某种原因,我将operator%=定义为virtual.或者,如果我要预先导出Primitive< float>从一个DLL来避免链接错误,即使我从未在Primitive< float>上调用operator%=,编译器也会抱怨.如果它只是为Primitive< float>的vtable(引发异常?)中的运算符%=填充虚拟值,那么一切都会好的.
最佳答案 将虚拟内容放入可选择的基类中……
struct Jumper
{
virtual void Jump =0;
};
struct Crawler
{
virtual void Crawl() =0;
};
struct JumperCrawler:
public Jumper,
public Crawler
{
};
template<typename T, typename Methods>
class ICanBoostJumpingAndCrawling :
public Methods
{
T t;
};
现在,您可以将ICanBoostJumpingAndCrawling与Jumper,Crawler或JumperCrawler一起用作Methods模板参数;意识到你需要从它派生,以便你可以在子类中实现跳跃和/或爬行.
仅供参考,这使得“ICanBoostJumpingAndCrawling”这个名称完全具有误导性,因为它可能会也可能不会这样做;这意味着它应该被重命名为“Booster”之类的东西.