来自Addison Wesley: C++模板
成员函数模板不能声明为虚的。施加此约束是因为虚拟函数调用机制的通常实现使用固定大小的表,每个虚拟函数具有一个条目。但是,成员函数模板的实例化数量在整个程序被翻译之前是不固定的。
上面的引述是否意味着模板有静态绑定,虚函数有动态绑定,这就是不能有虚函数模板的原因?请看是否可以用外行人的语言进行解释。
发布于 2011-04-21 18:32:07
考虑一下:
struct X
{
template <typename T>
T incr(const T& t)
{
return t + 1;
}
};
当incr()
应用于不同的T类型时,会生成新的函数。假设在app.c++
中你有:
X x;
x.incr(7); // incr<int>()
x.incr(7.0); // incr<double>()
x.incr("hello"); // incr<const char*>()
然后,当它编译app.c++
时,它看到了3个函数-如果incr
被允许为virtual
-它可以在X的虚拟分派表中为上面的3个实例化腾出空间。然后假设它在运行时加载一个共享库,该库的代码有2个uint32_t
和std::string::const_iterator
的X::incr
瞬间。dlopen()
需要为已经创建的对象增加现有的虚拟分派表,以便为两个新功能腾出空间。听起来并不太可怕,但请考虑:
因此,在非常罕见的情况下,这可能是有用的,这不值得妥协,也不值得让更常见的非模板化虚拟实例复杂化。
发布于 2011-04-21 18:28:45
是,也不是。
解决虚函数调用的最流行的方法是使用表("vtable"),其中每个虚函数都映射到表中的一个索引。这或多或少要求您知道表的大小。
有了模板,可以在不同的模块中根据需要创建新的函数。然后,您要么必须说服链接器在确定函数的最终数量后构建表,要么在运行时使用某种运行时结构来搜索可用的函数。
在许多系统上,链接器是操作系统的一部分,对C++一无所知,因此该选项是有限的。运行时搜索当然会对性能产生负面影响,可能对所有虚拟函数都是如此。
因此,最终决定将虚拟模板引入到语言中是不值得的。
发布于 2011-04-21 18:13:21
上面的引述是否意味着模板有静态绑定,虚函数有动态绑定,这就是不能有虚函数模板的原因吗?
基本上是这样的。更具体地说,当生成支持动态绑定的代码时,静态绑定会导致问题。
当编译器编译基类时,它会找到一个虚函数并决定创建一个虚函数表-这将用于实现动态绑定:当在派生实例上调用虚函数时,编译后的代码跟随实例中的指针指向派生类的虚函数表,然后是该表中的指针指向虚函数的实现。该表必须包括所有可能调用的虚函数。现在,假设我们创建了一个模板化的虚函数。对于模板的每个实例化,函数表都需要一个条目,因为这些函数中的任何一个都可以在运行时调用。但是,在生成虚拟函数表时,不能(通常)收集关于用什么类型实例化模板的信息。(至少,在不使用C++编译模型的情况下不是这样。)
https://stackoverflow.com/questions/5742531
复制相似问题