虚拟表/调度表

发布于 2024-11-18 23:59:47 字数 307 浏览 5 评论 0原文

据我对CPP的了解,每个类都有自己的vtable。

然而维基百科链接提到:

对象的调度表将 包含对象的地址 动态绑定方法。方法 调用是通过获取 方法的地址来自对象的地址 调度表。调度表是 对于属于的所有对象都相同 同一个类,因此 通常在他们之间共享。

有人可以解释一下吗?

谢谢 !

From what I know of CPP, each class has its own vtable.

However this wikipedia link mentions:

An object's dispatch table will
contain the addresses of the object's
dynamically bound methods. Method
calls are performed by fetching the
method's address from the object's
dispatch table. The dispatch table is
the same for all objects belonging to
the same class, and is therefore
typically shared between them.

Can someone please shed some light.

Thanks !

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

一口甜 2024-11-25 23:59:47

有时用一个例子更容易理解:

class PureVirtual {
   public:
       virtual void methodA() = 0;
       virtual void methodB() = 0;
};

class Base : public PureVirtual {
   public:
        virtual void methodA();
        void methodC();
   private:
        int x;
 };

 class Derived : public Base {
    public:
         virtual void methodB();
    private:
         int y;
 };

因此,给定一个 Derived 类型的对象,它可能看起来像:

                         ------------
 Known offset for vtable |  0xblah  | -------> [Vtable for type "Derived"]
                         ------------
 Known offset for x      |  3       |
                         ------------
 Known offset for y      |  2       |
                         ------------

“Derived”类型的 Vtable 看起来像这样:

                            ------------
 Known offset for "methodA" | 0xblah1   | ------> methodA from Base
                            -------------
 Known offset for "methodB" | 0xblah2   | ------> methodB from Derived
                            -------------

请注意,由于“methodC”不是虚拟的,所以它不在 vtable 中根本不。另请注意,Derived 类的所有实例都将具有指向同一共享 vtable 对象的 vtable 指针(因为它们具有相同的类型)。

尽管 C++ 和 Java 的实现略有不同,但思想并非不兼容。从概念的角度来看,主要区别在于 Java 方法是“虚拟的”,除非声明为“final”。在 C++ 中,必须显式给出关键字“virtual”才能使函数位于 vtable 中。任何不在 vtable 中的内容都将使用对象的编译时类型而不是运行时类型进行分派。

It's sometimes easier to understand with an example:

class PureVirtual {
   public:
       virtual void methodA() = 0;
       virtual void methodB() = 0;
};

class Base : public PureVirtual {
   public:
        virtual void methodA();
        void methodC();
   private:
        int x;
 };

 class Derived : public Base {
    public:
         virtual void methodB();
    private:
         int y;
 };

So, given an object of type Derived it might look like:

                         ------------
 Known offset for vtable |  0xblah  | -------> [Vtable for type "Derived"]
                         ------------
 Known offset for x      |  3       |
                         ------------
 Known offset for y      |  2       |
                         ------------

With the Vtable for type "Derived" looking something like:

                            ------------
 Known offset for "methodA" | 0xblah1   | ------> methodA from Base
                            -------------
 Known offset for "methodB" | 0xblah2   | ------> methodB from Derived
                            -------------

Note that since "methodC" was not virtual, it is not in the vtable at all. Also note that all instances of class Derived will have a vtable pointer to the same, shared vtable object (since they have the same type).

Though the implementations for C++ and Java are slightly different, the ideas are not incompatible. The key difference, from a conceptual standpoint, is that Java methods are "virtual" unless declared "final". In C++ the keyword "virtual" must be given explicitly for the function to be in the vtable. Anything not in vtable will be dispatched using the compile-time types rather than the runtime type of the object.

与往事干杯 2024-11-25 23:59:47

是的,编译器和运行时对虚拟方法的处理方式不同。

Java: java 中的所有方法默认都是虚拟的。这意味着在继承中使用时任何方法都可以被重写,除非该方法被声明为final或static。

VM 规范

Java虚拟机没有
授权任何特定的内部
对象的结构。书签
有规定:在 Sun 的一些
Java虚拟的实现
机器,对类的引用
实例是一个指向句柄的指针
本身是一对指针:一个指向一个
包含方法的表
对象和指向类的指针
代表类型的对象
对象,另一个到内存
从堆中为对象分配
数据。


C++:

每当类成员函数被声明为 virtual 时,编译器都会创建一个
内存中的虚拟表,其中包含声明为的所有函数指针
虚拟在该类中。这使得运行时多态性成为可能(即找出所需的
运行时函数)。虚函数表还有一个额外的指针
vtable 的对象。由于这个额外的指针和虚表增加了大小
对于对象,类设计者需要明智地声明函数为虚函数。

在基础对象指针上调用方法时的事件顺序是:

  • 获取 vtable 指针(此 vtable 指针指向 vtable 的开头)。
  • 使用 offset 获取 vtable 中的函数指针。

通过vtable指针间接调用该函数。

Yes, virtual methods are treated differently by the compiler and the runtime.

Java : All methods in java are virtual by default. That means that any method can be overridden when used in inheritance, unless that method is declared as final or static.

From the VM Specification,

The Java virtual machine does not
mandate any particular internal
structure for objects. The book mark
there states: In some of Sun's
implementations of the Java virtual
machine, a reference to a class
instance is a pointer to a handle that
is itself a pair of pointers: one to a
table containing the methods of the
object and a pointer to the Class
object that represents the type of the
object, and the other to the memory
allocated from the heap for the object
data.


C++ :

Whenever a class member function is declared as virtual, the compiler creates a
virtual table in memory which contains all function pointers that are declared as
virtual in that class. This enables run time polymorphism (i.e. finding out the desired
function at run time). Virtual function tables also have an additional pointer in the
object to the vtable. As this additional pointer and the vtable increases the size of
the object, a class designer needs to be judicious about declaring functions virtual.

The sequence of events upon calling a method on the base object pointer is :

  • Get vtable pointer (this vtable pointer points to the beginning of the vtable).
  • Get the function pointers in the vtable using offset.

Invoke the function indirectly through the vtable pointer.

弥枳 2024-11-25 23:59:47

每个具有虚函数的类(即在 Java 中只是“每个类”)都有自己的vtable。每个对象都隐藏了对其类 vtable 的引用。因此,同一类的对象具有相同的引用。

当您调用虚拟方法时,编译器通常会进行查找:

obj.method(args);

被翻译成某种东西

obj.vtable[idx_method](obj, args);

有时,如果编译器可以推断出特定类型的对象,它可以发出静态调用而不是虚拟方法。因此,代码

MyObject obj(ctor_args);
....
obj.method(args);

可以转换为

MyObject_method(obj, args);

通常比虚拟调用执行得更快的代码。

Every class having virtual functions (i.e. in Java it's just 'every class') has its own vtable. Each object has hidden a reference to it's class vtable. So, objects of the same class have identical references.

When you make call of virtual method compiler usually makes a lookup:

obj.method(args);

is translated into something

obj.vtable[idx_method](obj, args);

Sometimes, if compiler can deduce particular type of object, it can emit static call instead of virtual. So, code

MyObject obj(ctor_args);
....
obj.method(args);

can be translated into

MyObject_method(obj, args);

Which will usually execute faster than virtual call.

゛清羽墨安 2024-11-25 23:59:47

该引用指出每个对象都有一个调度表,该表可以在类之间共享,因为它们对于同一类的所有实例都是相同的。 IE 每个类都有它自己的 vtable。

That quote is pointing out that each object has a dispatch table, which can be shared among the class since they are the same for all instances of the same class. I.E. Each class has it's own vtable.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文