Implementation
An object's virtual method 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 virtual method table. The virtual method table is the same for all objects belonging to the same class, and is therefore typically shared between them. Objects belonging to type-compatible classes (for example siblings in an inheritance hierarchy) will have virtual method tables with the same layout: the address of a given method will appear at the same offset for all type-compatible classes. Thus, fetching the method's address from a given offset into a virtual method table will get the method corresponding to the object's actual class. TheExample
Consider the following class declarations inb2
:G++'s -fdump-class-hierarchy
(starting with version 8: -fdump-lang-class
) argument can be used to dump virtual method tables for manual inspection. For AIX VisualAge XlC compiler, use -qdump_class_hierarchy
to dump class hierarchy and virtual function table layout.
b2: +0: pointer to virtual method table of B2 +4: value of int_in_b2 virtual method table of B2: +0: B2::f2()and the following memory layout for the object
d
:
d: +0: pointer to virtual method table of D (for B1) +4: value of int_in_b1 +8: pointer to virtual method table of D (for B2) +12: value of int_in_b2 +16: value of int_in_d Total size: 20 Bytes. virtual method table of D (for B1): +0: B1::f1() // B1::f1() is not overridden virtual method table of D (for B2): +0: D::f2() // B2::f2() is overridden by D::f2() // The location of B2::f2 is not in the virtual method table for DNote that those functions not carrying the keyword
virtual
in their declaration (such as fnonvirtual()
and d()
) do not generally appear in the virtual method table. There are exceptions for special cases as posed by the B1
and B2
. They are necessary to ensure delete d
can free up memory not just for D
, but also for B1
and B2
, if d
is a pointer or reference to the types B1
or B2
. They were excluded from the memory layouts to keep the example simple.
Overriding of the method f2()
in class D
is implemented by duplicating the virtual method table of B2
and replacing the pointer to B2::f2()
with a pointer to D::f2()
.
Multiple inheritance and thunks
The g++ compiler implements theB1
and B2
in class D
using two virtual method tables, one for each base class. (There are other ways to implement multiple inheritance, but this is the most common.) This leads to the necessity for "pointer fixups", also called d
and b1
will point to the same memory location after execution of this code, b2
will point to the location d+8
(eight bytes beyond the memory location of d
). Thus, b2
points to the region within d
that "looks like" an instance of B2
, i.e., has the same memory layout as an instance of B2
.
Invocation
A call tod->f1()
is handled by dereferencing d
's D::B1
vpointer, looking up the f1
entry in the virtual method table, and then dereferencing that pointer to call the code.
Single inheritance
In the case of single inheritance (or in a language with only single inheritance), if the vpointer is always the first element in d
(as it is with many compilers), this reduces to the following pseudo-C++:
*d
refers to the virtual method table of D
and /code> refers to the first method in the virtual method table. The parameter d
becomes the "this
" pointer to the object.
Multiple inheritance
In the more general case, calling B1::f1()
or D::f2()
is more complicated:
(*(*(d 0*pointer to virtual method table of D (for B1)*/) )(d) /* Call d->f1() */
(*(*(d 8*pointer to virtual method table of D (for B2)*/) )(d+8) /* Call d->f2() */
The call to d->f1()
passes a B1
pointer as a parameter. The call to d->f2()
passes a B2
pointer as a parameter. This second call requires a fixup to produce the correct pointer. The location of B2::f2
is not in the virtual method table for D
.
By comparison, a call to d->fnonvirtual()
is much simpler:
(*B1::fnonvirtual)(d)
Efficiency
A virtual call requires at least an extra indexed dereference and sometimes a "fixup" addition, compared to a non-virtual call, which is simply a jump to a compiled-in pointer. Therefore, calling virtual functions is inherently slower than calling non-virtual functions. An experiment done in 1996 indicates that approximately 6–13% of execution time is spent simply dispatching to the correct function, though the overhead can be as high as 50%. The cost of virtual functions may not be so high on modern architectures due to much larger caches and better branch prediction
In computer architecture, a branch predictor is a digital circuit that tries to guess which way a branch (e.g., an if–then–else structure) will go before this is known definitively. The purpose of the branch predictor is to improve the flow ...
.
Furthermore, in environments where JIT compilation is not in use, virtual function calls usually cannot be inlined. In certain cases it may be possible for the compiler to perform a process known as ''devirtualization'' in which, for instance, the lookup and indirect call are replaced with a conditional execution of each inlined body, but such optimizations are not common.
To avoid this overhead, compilers usually avoid using virtual method tables whenever the call can be resolved at compile time
In computer science, compile time (or compile-time) describes the time window during which a computer program is compiled.
The term is used as an adjective to describe concepts related to the context of program compilation, as opposed to concept ...
.
Thus, the call to f1
above may not require a table lookup because the compiler may be able to tell that d
can only hold a D
at this point, and D
does not override f1
. Or the compiler (or optimizer) may be able to detect that there are no subclasses of B1
anywhere in the program that override f1
. The call to B1::f1
or B2::f2
will probably not require a table lookup because the implementation is specified explicitly (although it does still require the 'this'-pointer fixup).
Comparison with alternatives
The virtual method table is generally a good performance trade-off to achieve dynamic dispatch, but there are alternatives, such as binary tree dispatch, with higher performance but different costs.Zendra, Olivier and Driesen, Karel
"Stress-testing Control Structures for Dynamic Dispatch in Java"
pp. 105–118, Proceedings of the USENIX 2nd Java Virtual Machine Research and Technology Symposium, 2002 (JVM '02)
However, virtual method tables only allow for single dispatch
In computer science, dynamic dispatch is the process of selecting which implementation of a polymorphic operation (method or function) to call at run time. It is commonly employed in, and considered a prime characteristic of, object-oriented ...
on the special "this" parameter, in contrast to multiple dispatch
Multiple dispatch or multimethods is a feature of some programming languages in which a function or method can be dynamically dispatched based on the run-time (dynamic) type or, in the more general case, some other attribute of more than one of ...
(as in CLOS
Clos may refer to:
People
* Clos (surname)
Other uses
* CLOS, Command line-of-sight, a method of guiding a missile to its intended target
* Clos network, a kind of multistage switching network
* Clos (vineyard), a walled vineyard; used in Fran ...
, Dylan, or Julia
Julia is usually a feminine given name. It is a Latinate feminine form of the name Julio and Julius. (For further details on etymology, see the Wiktionary entry "Julius".) The given name ''Julia'' had been in use throughout Late Antiquity (e.g ...
), where the types of all parameters can be taken into account in dispatching.
Virtual method tables also only work if dispatching is constrained to a known set of methods, so they can be placed in a simple array built at compile time, in contrast to duck typing
Duck typing in computer programming is an application of the duck test—"If it walks like a duck and it quacks like a duck, then it must be a duck"—to determine whether an object can be used for a particular purpose. With nominative t ...
languages (such as Smalltalk
Smalltalk is an object-oriented, dynamically typed reflective programming language. It was designed and created in part for educational use, specifically for constructionist learning, at the Learning Research Group (LRG) of Xerox PARC by Alan Ka ...
, Python
Python may refer to:
Snakes
* Pythonidae, a family of nonvenomous snakes found in Africa, Asia, and Australia
** ''Python'' (genus), a genus of Pythonidae found in Africa and Asia
* Python (mythology), a mythical serpent
Computing
* Python (pro ...
or JavaScript
JavaScript (), often abbreviated as JS, is a programming language that is one of the core technologies of the World Wide Web, alongside HTML and CSS. As of 2022, 98% of Website, websites use JavaScript on the Client (computing), client side ...
).
Languages that provide either or both of these features often dispatch by looking up a string in a hash table
In computing, a hash table, also known as hash map, is a data structure that implements an associative array or dictionary. It is an abstract data type that maps keys to values. A hash table uses a hash function to compute an ''index'', als ...
, or some other equivalent method. There are a variety of techniques to make this faster (e.g., interning/tokenizing method names, caching lookups, just-in-time compilation
In computing, just-in-time (JIT) compilation (also dynamic translation or run-time compilations) is a way of executing computer code that involves compilation during execution of a program (at run time) rather than before execution. This may cons ...
).
See also
*Virtual function
In object-oriented programming, in languages such as C++, and Object Pascal, a virtual function or virtual method is an inheritable and overridable function or method for which dynamic dispatch is facilitated. This concept is an important part o ...
*Virtual inheritance
Virtual inheritance is a C++ technique that ensures only one copy of a base classs member variables are inherited by grandchild derived classes. Without virtual inheritance, if two classes B and C inherit from a class A, and a class D inherits fr ...
*Branch table
In computer programming, a branch table or jump table is a method of transferring program control ( branching) to another part of a program (or a different program that may have been dynamically loaded) using a table of branch or jump instruction ...
Notes
References
* Margaret A. Ellis and Bjarne Stroustrup
Bjarne Stroustrup (; ; born 30 December 1950) is a Danish computer scientist, most notable for the invention and development of the C++ programming language. As of July 2022, Stroustrup is a professor of Computer Science at Columbia University. ...
(1990) The Annotated C++ Reference Manual. Reading, MA: Addison-Wesley. ()
{{DEFAULTSORT:Virtual Method Table
Method (computer programming)
Articles with example C++ code