首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >成员函数模板不能声明为虚的-来自Addison Wesley: C++模板

成员函数模板不能声明为虚的-来自Addison Wesley: C++模板
EN

Stack Overflow用户
提问于 2011-04-21 18:04:51
回答 6查看 8.1K关注 0票数 16

来自Addison Wesley: C++模板

成员函数模板不能声明为虚的。施加此约束是因为虚拟函数调用机制的通常实现使用固定大小的表,每个虚拟函数具有一个条目。但是,成员函数模板的实例化数量在整个程序被翻译之前是不固定的。

上面的引述是否意味着模板有静态绑定,虚函数有动态绑定,这就是不能有虚函数模板的原因?请看是否可以用外行人的语言进行解释。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2011-04-21 18:32:07

考虑一下:

代码语言:javascript
复制
struct X
{
    template <typename T>
    T incr(const T& t)
    {
        return t + 1;
    }
};

incr()应用于不同的T类型时,会生成新的函数。假设在app.c++中你有:

代码语言:javascript
复制
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_tstd::string::const_iteratorX::incr瞬间。dlopen()需要为已经创建的对象增加现有的虚拟分派表,以便为两个新功能腾出空间。听起来并不太可怕,但请考虑:

  • 调用虚拟函数的每一小块代码都必须知道这些函数的地址是否在运行时被某些偏移量冲撞(由于动态加载额外的实例化),因此在每个虚拟函数中都有额外的内存和性能成本。如果有多个继承,或者派生类本身是派生的,编译器可能想要为整个虚拟函数集创建一个单独的虚拟分派表(一种选择,有许多用于实现虚拟分派的):在这种情况下,新的虚拟函数将替换其他类的虚拟函数,或者需要与现有的虚拟函数分离。同样,在任何方案中都有更多的运行时开销来管理这一点。

因此,在非常罕见的情况下,这可能是有用的,这不值得妥协,也不值得让更常见的非模板化虚拟实例复杂化。

票数 7
EN

Stack Overflow用户

发布于 2011-04-21 18:28:45

是,也不是。

解决虚函数调用的最流行的方法是使用表("vtable"),其中每个虚函数都映射到表中的一个索引。这或多或少要求您知道表的大小。

有了模板,可以在不同的模块中根据需要创建新的函数。然后,您要么必须说服链接器在确定函数的最终数量后构建表,要么在运行时使用某种运行时结构来搜索可用的函数。

在许多系统上,链接器是操作系统的一部分,对C++一无所知,因此该选项是有限的。运行时搜索当然会对性能产生负面影响,可能对所有虚拟函数都是如此。

因此,最终决定将虚拟模板引入到语言中是不值得的。

票数 24
EN

Stack Overflow用户

发布于 2011-04-21 18:13:21

上面的引述是否意味着模板有静态绑定,虚函数有动态绑定,这就是不能有虚函数模板的原因吗?

基本上是这样的。更具体地说,当生成支持动态绑定的代码时,静态绑定会导致问题。

当编译器编译基类时,它会找到一个虚函数并决定创建一个虚函数表-这将用于实现动态绑定:当在派生实例上调用虚函数时,编译后的代码跟随实例中的指针指向派生类的虚函数表,然后是该表中的指针指向虚函数的实现。该表必须包括所有可能调用的虚函数。现在,假设我们创建了一个模板化的虚函数。对于模板的每个实例化,函数表都需要一个条目,因为这些函数中的任何一个都可以在运行时调用。但是,在生成虚拟函数表时,不能(通常)收集关于用什么类型实例化模板的信息。(至少,在不使用C++编译模型的情况下不是这样。)

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5742531

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档