例如,为什么没有语言支持来检查vtable?为什么我不能用新的成员函数替换成员函数?我有一种直觉,就是有办法很好地利用这些功能。
还有其他语言允许我做这些事情吗?
答案 0 :(得分:17)
因为它是编译器的实现细节。该实现可能会发生变化,任何依赖它的代码都会变得脆弱。
答案 1 :(得分:8)
C ++是一种你永远不会“付钱”你不使用的语言。这种运行时支持与这种哲学背道而驰。
有很多语言(在频谱的更动态的一端)支持它。
答案 2 :(得分:8)
因为它不必作为VTable
实现,尽管通常是这种情况。简而言之,C ++中没有VTable
这样的东西!
答案 3 :(得分:5)
主要原因是保持vtable作为实现细节允许任何具体实现在其认为合适时优化它;这意味着它可以例如如果可以证明对给定方法(或所有方法)没有虚拟调用,则完全修剪甚至消除vtable。或者它可以用if-else类型检查替换vtable调度,例如,它看到只有少数几种选择(这可能是有利的,因为分支预测在这种情况下会起作用,但不适用于vtable,也因为if-else分支可以内联)。它可以对vtable中的方法进行重新排序,使得最常见的方法更早出现,或者使那些通常被称为一个接一个的方法填充vtable中的相邻插槽以利用缓存。等等等等。当然,所有这些实现也会使vtable布局完全不可预测,因此如果要(通过语言规范)将其暴露给实现,则无用。
同样,vtable并不像听起来那么简单。例如,编译器通常必须生成thunks来修复this
指针,用于虚拟继承,或多重继承与协变返回类型相结合。这也是没有“单一最佳方式”去做的事情(这就是为什么不同的编译器以不同的方式做到这一点),并且标准化它实际上需要以特定的方式解决。
也就是说,“vtable切换”是一种潜在有用的技术,如果作为更高级别的构造公开(这样仍然可以进行优化)。有关示例,请参阅UnrealScript,它允许为类定义多个states(一个默认名称,另一个名称),并覆盖命名状态中的某些方法。派生类可以覆盖现有状态中的更多方法,或者添加它们自己的状态并覆盖它们。此外,状态可以扩展其他状态(因此,如果某个方法没有被覆盖特定状态,它将回退到“父”状态,依此类推,直到链达到默认状态)。对于演员建模(游戏本质上是这样),这一切都很有意义,这就是UnrealScript拥有它的原因。所有这一切的明显有效的实现机制是vtable切换,每个状态都有一个单独的vtable。
答案 4 :(得分:3)
JavaScript,Python和Ruby都可以做到这一点。在这些语言中,类和实例定义在运行时是可变的。抽象地说,每个对象和类型都是可以检查和更新的成员变量和方法的字典。
这在C ++中是不可能的,因为它需要能够重写生成的二进制代码,这可能会带来很大的性能成本。
答案 5 :(得分:3)
Vtable仅在某些编译器的某些情况下存在(即它们未在标准中指定,而是实现细节)。即使它们确实存在,它们也只在您拥有虚函数并且需要间接实现多态时才会发生。如果不需要,可以优化它们,从而节省呼叫间接的开销。
可悲的是(或者,根据你对此事的看法;-),C ++并不是为了支持猴子补丁而设计的。在某些情况下(例如COM),vtable是实现的一部分,您可能能够在幕后捅。但是,永远不会支持或移植它。
答案 6 :(得分:2)
我相信你可以在像Python这样的动态语言中做类似的事情:
>>> class X():
... def bar(self): print "bar"
...
>>> x = X()
>>> x.bar()
bar
>>> def foo(x): print "foo"
...
>>> X.bar = foo
>>> x.bar()
foo
与C ++这样的静态语言的区别在于解释器在运行时查找所有名称,然后决定要做什么。
在C ++中,“替换成员函数与另一个成员函数”可能有其他解决方案,其中最简单的可能是使用函数指针:
#include <iostream>
class X;
typedef void (*foo_func)(const X&);
void foo(const X&) { std::cout << "foo\n"; }
void bar(const X&) { std::cout << "bar\n"; }
class X
{
foo_func f;
public:
X(): f(foo) {}
void foobar() { f(*this); }
void switch_function(foo_func new_foo) { f = new_foo; }
};
int main()
{
X x;
x.foobar();
x.switch_function(bar);
x.foobar();
}
(foo和bar不使用X&amp;参数,在本例中,类似于Python示例)
答案 7 :(得分:1)
我正在研究一种暴露vtable的静态编译语言,并且相信我有很多hair要公开。
答案 8 :(得分:1)
也许你想要的是在不使用C ++的内置工具的情况下实现自己的vtable。使用指向成员函数的指针(ptmf)可以获得很多乐趣!
使用vtable内省找到编译语言会很困难,因为需求很少而且实现起来也不容易。但是,对于解释型语言,情况恰恰相反。
答案 9 :(得分:1)
还有其他语言吗? 那里允许我这样做 东西?
Objective-C(以及Objective-C ++)允许运行时替换已编译的方法。它可以是静态和动态技术的最佳组合,也可以是最糟糕的组合,具体取决于您的要求。
答案 10 :(得分:0)
正如其他人所指出的那样,C ++标准中没有“vtable”的概念,因为它只是一种几乎普遍的实现技术,就像名称修改一样。
如果您正在寻找能够以编译语言动态重新定义函数,您可能会对Common Lisp感兴趣。必须有其他语言,但我能想到的唯一其他语言要么具有静态继承和功能,要么在性能上花费很大的代价。