1

例如,为什么没有语言支持来检查 vtable?为什么我不能用新的成员函数替换成员函数?我有一种直觉,有办法很好地利用这些功能。

有没有其他语言可以让我做这样的事情?

4

11 回答 11

17

因为它是编译器的一个实现细节。该实现可能会改变,任何依赖它的代码充其量都是脆弱的。

于 2009-09-12T18:28:10.657 回答
8

C++ 是一种你永远不会为你不使用的东西“付费”的语言。这种运行时支持与该理念背道而驰。

有很多语言(在更动态的一端)支持这一点。

于 2009-09-12T18:28:16.250 回答
8

因为它不必实现为 a VTable,尽管通常是这种情况。简而言之,VTable在 C++ 中没有这样的东西!

于 2009-09-12T18:33:48.830 回答
5

主要原因是保留 vtable 作为实现细节允许任何具体的实现在它认为合适的时候对其进行优化;这意味着如果它可以证明给定方法(或所有方法)没有虚拟调用,它可以例如修剪甚至完全消除 vtable。或者它可以用 if-else 类型检查替换 vtable 调度,例如,如果它看到只有几个替代方案(这可能是有利的,因为分支预测在这种情况下将起作用,但不适用于 vtables,并且还因为 if-else然后可以内联分支)。它可以对 vtable 中的方法进行重新排序,以便最常调用的方法更早出现,或者使通常被调用的方法一个接一个地填充 vtable 中的相邻槽以利用缓存。等等等等。当然,

同样,vtable 并不像听起来那么简单。例如,编译器通常必须生成 thunk 来修复this诸如虚拟继承或结合协变返回类型的多重继承的指针。这又是没有“单一最佳方式”的事情(这就是为什么不同的编译器会以不同的方式做事),并且标准化它实际上需要以特定方式解决。

也就是说,“vtable 切换”是一种潜在有用的技术,如果公开为更高级别的构造(因此仍然可以进行优化)。例如,请参阅 UnrealScript,它允许定义多个状态对于一个类(一个默认值,另一个命名),并覆盖命名状态中的某些方法。派生类可以覆盖现有状态中的更多方法,或者添加自己的状态并在其中覆盖。此外,状态可以扩展其他状态(因此,如果一个方法没有为特定状态覆盖,它会回退到“父”状态,依此类推,直到链达到默认状态)。对于演员建模(本质上是游戏)来说,这一切都很有意义,这就是 UnrealScript 拥有它的原因。所有这一切的明显有效的实现机制是 vtable 切换,每个状态都有一个单独的 vtable。

于 2010-01-11T21:48:52.027 回答
3

JavaScript、Python 和 Ruby 都可以做到这一点。在这些语言中,类和实例定义在运行时是可变的。抽象地说,每个对象和类型都是可以检查和更新的成员变量和方法的字典。

这在 C++ 中是不可能的,因为它需要能够重写生成的二进制代码,这会带来巨大的性能成本。

于 2009-09-12T19:02:12.580 回答
3

Vtables 仅存在于某些编译器中的某些情况下(即它们没有在标准中指定,而是在实现细节中指定)。即使它们确实存在,它们也只会在您拥有虚函数并且需要间接实现多态性时才会出现。当不需要这样做时,可以对其进行优化,从而节省调用间接的开销。

可悲的是(或其他情况,取决于您对此事的看法;-),C++ 并非旨在支持猴子补丁。在某些情况下(例如 COM),vtable 是实现的一部分,您也许可以在幕后进行讨论。但是,这永远不会被支持或移植。

于 2009-09-12T20:42:28.757 回答
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& 参数,在此示例中,类似于 Python 示例)

于 2009-09-12T19:09:26.980 回答
1

我正在研究一种公开vtable的静态编译语言,相信我要公开它有点麻烦。

于 2009-09-12T19:12:46.410 回答
1
  • 任何你可以在 C++ 中做的事情,你都可以在直接的 C 中做一点点肘部油脂。
  • 任何适度和合理的 C 程序都应该用 C++ 编译。

也许您想要的是在不使用 C++ 的内置工具的情况下实现自己的 vtable。使用指向成员函数 (ptmf) 的指针会给您带来很多乐趣!

您将很难找到带有 vtable 内省的编译语言,因为需求很少并且不容易实现。但是,对于解释型语言,情况正好相反。

于 2010-01-11T20:33:14.723 回答
1

有没有其他语言可以让我做这样的事情?

Objective-C(以及 Objective-C++)允许运行时替换已经编译的方法。它要么是静态和动态技术的最佳组合,要么是最差的,这取决于你问谁。

于 2010-01-11T21:20:36.190 回答
0

正如其他人指出的那样,C++ 标准中没有“vtable”的概念,因为它只是一种几乎通用的实现技术,很像名称修饰。

如果您正在寻找能够在编译语言中动态地重新定义函数,您可能会对 Common Lisp 感兴趣。必须有其他语言,但我能想到的唯一其他语言要么具有静态继承和函数,要么以巨大的性能成本进行解释。

于 2010-01-11T21:10:20.703 回答