If classes with virtual functions are implemented using vtables, how is a class without virtual functions implemented?

In particular, shouldn't there be some kind of function pointer in place?

+6
c ++ virtual-functions
source share
9 answers

Non-virtual member functions are just syntactic sugar, since they are almost similar to a regular function, but with access control and an implicit object parameter.

struct A { void foo (); void bar () const; }; 

basically the same as:

 struct A { }; void foo (A * this); void bar (A const * this); 

Vtable is required so that we call the correct function for our particular instance of the object. For example, if we have:

 struct A { virtual void foo (); }; 

The implementation of "foo" may come close to something like:

 void foo (A * this) { void (*realFoo)(A *) = lookupVtable (this->vtable, "foo"); (realFoo)(this); // Make the call to the most derived version of 'foo' } 
+12
source share

I think the phrase "classes with virtual functions are implemented using vtables" is misleading.

The phrase makes it sound like classes with virtual functions are implemented "in order A" and classes without virtual functions are implemented "in order B".

In fact, classes with virtual functions, in addition to being implemented as classes, also have vtable. Another way to see this is with "vtables" to implement part of the "virtual function of the" class ".

More on how they work:

All classes (with virtual or non-virtual methods) are structures. The only difference between a structure and a class in C ++ is that, by default, members are public in structs and private in classes. Because of this, I will use the term β€œclass” here to refer to both structures and classes. Remember that they are almost synonyms!

Data members

Classes (like structures) are just blocks of contiguous memory, where each element is stored in sequence. Please note that in some cases there will be gaps between members for reasons of processor architecture, so the block may be larger than the sum of its parts.

Methods

Methods or "member functions" are an illusion. Actually there is no such thing as a member function. A function is always a sequence of machine code instructions stored somewhere in memory. To make a call, the processor moves to this memory position and starts execution. We can say that all methods and functions are "global", and any indication to the contrary is a convenient illusion performed by the compiler.

Obviously, the method acts as if it belongs to a specific object, so it is clear that more is happening. To associate a specific method (function) call with a specific object, each member method has a hidden argument, which is a pointer to this object. The element is hidden in that you do not add it to your C ++ code yourself, but there is nothing magical about it - it is very real. When you say this:

 void CMyThingy::DoSomething(int arg); { // do something } 

The compiler really does this:

 void CMyThingy_DoSomething(CMyThingy* this, int arg) { /do something } 

Finally, when you write this:

 myObj.doSomething(aValue); 

the compiler says:

 CMyThingy_DoSomething(&myObj, aValue); 

No need for function pointers anywhere! The compiler already knows which method you are calling, so it calls it directly.

Static methods are even simpler. They do not have this pointer, so they execute exactly the same as you write them.

I.e! The rest is just convenient syntactic sugaring: the compiler knows which class the method belongs to, so it does not allow you to call a function without specifying which one. He also uses this knowledge to translate myItem to this->myItem when it is explicitly for this.

(yes, this is right: access to a member in a method is always performed indirectly using a pointer, even if you do not see it)

( Edit : deleted the last sentence and published separately so that it can be criticized separately)

+15
source share

Virtual methods are required if you want to use polymorphism. The virtual modifier places the method in VMT for late binding, and then at runtime it is determined which method is executed from this class.

If the method is not virtual, it is determined at compile time from which the class instance will be executed.

Function pointers are mainly used for callbacks.

+3
source share

If a class with a virtual function is implemented using vtable, then a class without a virtual function is implemented without vtable.

The vtable contains pointers to the functions necessary to send a call to the corresponding method. If the method is not virtual, the call goes to a class of a known type, and indirect call is not required.

+1
source share

For a non-virtual method, the compiler can generate a normal function call (for example, CALL to a specific address with the specified pointer passed as a parameter) or even embed it. For a virtual function, the compiler usually does not know at compile time where the address calls the code, so it generates code that looks for the address in the vtable at runtime, and then calls the method. True, even for virtual functions, the compiler can sometimes correctly resolve the correct code at compile time (for example, methods of local variables called without a pointer / reference).

+1
source share

(I pulled this section from my original answer so that it can be criticized separately. This is much more concise to the bottom of your question, so in a sense it is a much better answer)

No, there are no function pointers; instead, the compiler turns the problem inside out.

The compiler calls a global function with a pointer to the object instead of calling some function with a pointer inside the object

Why? Because it is usually much more effective. Indirect calls are expensive instructions.

+1
source share

There is no need for function pointers, since it cannot change at run time.

0
source share

Branches are created directly by compiled code for methods; just as if you had functions that are not part of any class, branches are generated directly to them.

0
source share

The compiler / linker directly binds which methods will be called. No vtable pointer needed. By the way, what does this have to do with stack versus heap?

0
source share

All Articles