java 虚拟表/调度表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6606481/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 16:35:56  来源:igfitidea点击:

Virtual table/dispatch table

javac++oopvirtual-functions

提问by codeObserver

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

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

However thiswikipedia 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 !

谢谢 !

回答by Michael Aaron Safyan

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:

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

                         ------------
 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:

类型“派生”的 Vtable 看起来像:

                            ------------
 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).

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

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.

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

回答by sgokhales

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.

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

From the VM Specification,

VM 规范

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.

Java 虚拟机不强制要求任何特定的对象内部结构。那里的书签指出:在 Sun 的一些 Java 虚拟机实现中,对类实例的引用是指向句柄的指针,句柄本身是一对指针:一个指向包含对象方法的表和一个指针到代表对象类型的 Class 对象,另一个到从堆中分配给对象数据的内存。



C++ :

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.

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

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.
  • 获取vtable指针(这个vtable指针指向vtable的开头)。
  • 使用偏移量获取 vtable 中的函数指针。

Invoke the function indirectly through the vtable pointer.

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

回答by elder_george

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.

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

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.

这通常比虚拟调用执行得更快。

回答by Jim Deville

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.

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