What happens when calling base functions from derived classes? [closed] - c++

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
Well my question is a bit trickier.
Let's say I have three classes like so:
class GrandFather
{
public:
virtual int DoSomething()
{
return 3;
}
};
class Father : public GrandFather
{
};
class Child : public Father
{
public:
virtual int DoSomething()
{
Father::DoSomething();
}
};
I have found in some references, that when calling a base function, the whole virtual mechanism isn't used, and name mangling takes place.
Now I want to know how this could be done.
The Child class has a pointer to its own vtable, which will indicate that upon calling DoSomething() the implementation of the child is called.
The Father class has a pointer to its own vtable as well, which will indicate that upon calling DoSomething() the implementation of GrandFather is called.
When I use Father::DoSomething() inside of Child, it should call GrandFather::DoSomething(),
but how can Child tell where the function is?
If name mangling is really used, then how? because there is no function with that name (something like _Father_DoSomething(this)).
Child must access the Father's vptr in order to get to GrandFather::DoSomething() , which as much as I know, he cannot.
This has been bothering me for quite some time, so I will appreciate the help very much.
thanks :)

Whenever you explicitly qualify the member function, you are saying you want to call that particular function in that particular class, and the virtual calling mechanism isn't used. Virtual calls only take place when you call a member function without qualifying it, it which case it uses the virtual mechanism to make the decision about which class's member function to use.
The fact that calling Father::DoSomething calls GrandFather::DoSomething is due to inheritance, which is a separate mechanism. If you refer to a member of the derived class and it isn't there, it goes up one level and looks in the base class for it. No virtual call is necessary there.

When you call Father::DoSomething from Child the compiler used compile time information to work out what to call. Because there isn't a version in Father it knows to call the one in GrandFather as it's the version that is effectivly in scope within Father.
When an overridden method calls down to a base implementation the vtable isn't used. The vtable is only used when you call a method via a pointer or reference. This is how all polymorphism is achieved in C++.
Name mangling doesn't have anything to do with this. Name mangling is basically how a method name is encoded so give a unique name for a method/function. No two methods/functions will have the same mangled name.

When a qualified name is used to name the function, the function
called is determined at compile time, using the static type of
the expression, and the name lookup starts at the location given
by the qualifier. Since the function to be called is determined
entirely by static lookup, there is no need to access any vtable
at all.

The g++ file_name.cpp -S command could provide enough info to have all vtable-related issues clear. Please check .s file produced:
Child has own vtable that contains Father vtable that, in own turn, contains vtable for GrandFather:
vtable for Child:
Child::DoSomething()
vtable for Father
vtable for Father:
GrandFather::DoSomething()
vtable for GrandFather
vtable for GrandFather:
GrandFather::DoSomething()
When I use Father::DoSomething() inside of Child, it should call
GrandFather::DoSomething(), but how can Child tell where the function
is?
vtable for Father has reference to the GrandFather::DoSomething(), so calling Father::DoSomething() you are actualli invoking GrandFather::DoSomething()

"Name mangling" has absolutely nothing to do with it. The technique known as "name mangling" belongs to completely different and irrelevant area. I don't know where you got the idea to involve it here.
Classes do not have any "pointers to vtable". Only specific objects (aka instances) of class types might have such pointers. Don't mix classes and objects of class type. In any case, "vtable pointers" is an implementation detail that does not exist at language level. It is completely unnecessary for understanding the behavior of the code at language level.
In your example you don't have any objects at all. You simply declared a bunch of classes. For this reason, it is to early to be taking about any "pointers to vtables". You don't have any pointers to any vtables in what you posted.
When it comes to the matter of Father::DoSomething() call, the issue of any "virtual tables" does not come into the picture at all, even as an implementation detail. Father::DoSomething() call uses a qualified name of the target function. Such qualified calls are always resolved directly, without involving any vtables. I.e. by doing Father::DoSomething() you are explicitly asking the compiler to ignore any polymorphism (ignore any "vtables") and directly perform a compile-time name lookup for name DoSomething in class Father. According to the rules of name lookup it will find function GrandFather::DoSomething() and call it.
If you actually declare an object, like
Child child;
then you will have a GrandFather subobject embedded into Father subobject embedded into the above Child object. All "vtable pointers" in those nested objects will point to the vtable of Child (in fact, in a typical implementation all these nested objects will share a single vtable pointer).
Now if you call
child.DoSomething()
this call will be resolved in accordance with vtable of Child and dispatched to Child::DoSomething() (most compilers will actually be smart enough to optimize the code and dispatch the call directly). However, as I said above, the qualified call to Father::DoSomething from inside Child::DoSomething is unconditionally performed directly, as you asked. It doesn't care about any vtable pointers. It just goes straight to GrandFather::DoSomething().
That's all there is to it.

Related

C++ should I use virtual methods?

Let me start by telling that I understand how virtual methods work (polymorphism, late-binding, vtables).
My question is whether or not I should make my method virtual. I will exemplify my dilemma on a specific case, but any general guidelines will be welcomed too.
The context:
I am creating a library. In this library I have a class CallStack that captures a call stack and then offers vector-like access to the captured stack frames. The capture is done by a protected method CaptureStack. This method could be redefined in a derived class, if the users of the library wish to implement another way to capture the stack. Just to be clear, the discussion to make the method virtual applies only to some methods that I know can be redefined in a derived class (in this case CaptureStack and the destructor), not to all the class methods.
Throughout my library I use CallStack objects, but never exposed as pointers or reference parameters, thus making virtual not needed considering only the use of my library.
And I cannot think of a case when someone would want to use CallStack as pointer or reference to implement polymorphism. If someone wants to derive CallStack and redefine CaptureStack I think just using the derived class object will suffice.
Now just because I cannot think polymorphism will be needed, should I not use virtual methods, or should I use virtual regardless just because a method can be redefined.
Example how CallStack can be used outside my library:
if (error) {
CallStack call_stack; // the constructor calls CaptureStack
for (const auto &stack_frame : call_stack) {
cout << stack_frame << endl;
}
}
A derived class, that redefines CaptureStack could be use in the same manner, not needing polymorphism:
if (error) {
// since this is not a CallStack pointer / reference, virtual would not be needed.
DerivedCallStack d_call_stack;
for (const auto &stack_frame : d_call_stack) {
cout << stack_frame << endl;
}
}
If your library saves the call stack during the constructor then you cannot use virtual methods.
This is C++. One thing people often get wrong when coming to C++ from another language is using virtual methods in constructors. This never works as planned.
C++ sets the virtual function table during each constructor call. That means that functions are never virtual when called from the constructor. The virtual method always points to the current class being constructed.
So even if you did use a virtual method to capture the stack the constructor code would always call the base class method.
To make it work you'd need to take the call out of the constructor and use something like:
CallStack *stack = new DerivedStack;
stack.CaptureStack();
None of your code examples show a good reason to make CaptureStack virtual.
When deciding whether you need a virtual function or not, you need to see if deriving and overriding the function changes the expected behavior/functionality of other functions that you're implementing now or not.
If you are relying on the implementation of that particular function in your other processes of the same class, like another function of the same class, then you might want to have the function as virtual. But if you know what the function is supposed to do in your parent class, and you don't want anybody to change it as far as you're concerned, then it's not a virtual function.
Or as another example, imagine somebody derives a class from you implementation, overrides a function, and passes that object as casted to the parent class to one of your own implemented functions/classes. Would you prefer to have your original implementation of the function or you want them to have you use their own overriden implementation? If the latter is the case, then you should go for virtual, unless not.
It's not clear to me where CallStack is being called. From
your examples, it looks like you're using the template method
pattern, in which the basic functionality is implemented in the
base class, but customized by means of virtual functions
(normally private, not protected) which are provided by the
derived class. In this case (as Peter Bloomfield points out),
the functions must be virtual, since they will be called from
within a member function of the base class; thus, with a static
type of CallStack. However: if I understand your examples
correctly, the call to CallStack will be in the constructor.
This will not work, as during construction of CallStack, the
dynamic type of the object is CallStack, and not
DerivedCallStack, and virtual function calls will resolve to
CallStack.
In such a case, for the use cases you describe, a solution using
templates may be more appropriate. Or even... The name of the
class is clear. I can't think of any reasonable case where
different instances should have different means of capturing the
call stack in a single program. Which suggests that link time
resolution of the type might be appropriate. (I use the
compilation firewall idiom and link time resolution in my own
StackTrace class.)
My question is whether or not I should make my method virtual. I will exemplify my dilemma on a specific case, but any general guidelines will be welcomed too.
Some guidelines:
if you are unsure, you should not do it. Lots of people will tell you that your code should be easily extensible (and as such, virtual), but in practice, most extensible code is never extended, unless you make a library that will be used heavily (see YAGNI principle).
you can use encapsulation in place of inheritance and type polymorphism (templates) as an alternative to class hierarchies in many cases (e.g. std::string and std::wstring are not two concrete implementations of a base string class and they are not inheritable at all).
if (when you are designing your code/public interfaces) you realize you have more than one class that "is an" implementation of another classes' interface, then you should use virtual functions.
You should almost certainly declare the method as virtual.
The first reason is that anything in your base class which calls CaptureStack will be doing so through a base class pointer (i.e. the local this pointer). It will therefore call the base class version of the function, even though a derived class masks it.
Consider the following example:
class Parent
{
public:
void callFoo()
{
foo();
}
void foo()
{
std::cout << "Parent::foo()" << std::endl;
}
};
class Child : public Parent
{
public:
void foo()
{
std::cout << "Child::foo()" << std::endl;
}
};
int main()
{
Child obj;
obj.callFoo();
return 0;
}
The client code using the class is only ever using a derived object (not a base class pointer etc.). However, it's the base class version of foo() that actually gets called. The only way to resolve that is to make foo() virtual.
The second reason is simply one of correct design. If the purpose of the derived class function is to override rather than mask the original, then it should probably do so unless there is a specific reason otherwise (such as performance concerns). If you don't do that, you're inviting bugs and mistakes in future, because the class may not act as expected.

How C++ object keeps information about its member functions

class A {
public :
void printSometext() {
std::cout << "printing A" << std::endl;
}
};
class B {
public :
void printSometext() {
std::cout << "printing B" << std::endl;
}
};
int main() {
A* a = new A();
a->printSometext();
return 0;
}
How C++ object keeps information about its member functions. Lets consider above code. When I call printSometext on object "a" how does it know what function to call and how it finds the right method.
When printing the size of the object it prints the summing size of its member variable (+allignments). So please provide some internal information how the member function call takes place.
Thanks,
Deimus
You have got the basics of C++ programming wrong. a does not know about printSomeText at the runtime, it is the compiler and linker which translates above code to binary code which performs these tasks. At runtime, there is just a bunch of instructions.
Well, that's an interesting question, but let me try to answer that in a very methodical manner !!!
let's say compiler has to resolve a call like this : *
a->someFunc();
*.
Now, compiler will go over following steps methodically.
1.) Firstly, compiler knows the declared type of variable a, so it will check whether the declared type of object a (lets call this, class A for time being), have a method with the name someFunc() and that it must be public. This method could either be declared in class A, or it could be a derived method from one of the base class(es) of class A, but it doesn't matter to compiler and it just checks for it's existence with it's access specifier being public.
Needless to say any error in this step will invite a compiler error.
2.) Secondly, once the method is validated to be a part of the class A, compiler has to resolve the call to the correct method, since many methods could be there with same name (thanks to function overloading). This process of resolving correct method is called overloading resolution. Compiler achieves this by matching the signatures of the called method with all the overloaded methods that are part of the class. So, of all the someFunc() s only the correct someFunc() (matching the signatures with called method) will be found and considered further.
3.) Now comes the difficult part, It may very well happen that someFunc() may have been overridden in one of the subclasses of the class A (lets call this class AA and needless to say it is some subclass of A), and that variable a (declared to be of type A) may actually be referring to an object of class AA, (this is permissible in C++ to enable polymorphism). Now, if the someFunc() method is declared to be of type virtual, in base class (i.e. Class A) and someFunc() has been overriden by subclass(es) of A (either in AA or classes between A and AA), the correct version of someFunc() have to be found out by the compiler.
Now, imagine you're the compiler and you have this task of finding whether the class AA has this method. Obviously, class AA will have this method since, it is a subclass of A and public access of A in class A has already been validated in Step 1 by the compiler !!! . But Alternatively, as mentioned in previous paragraph, someFunc() may be overriden by class AA (or any other class between A and AA), which is what compiler needs to catch. Therefore, you (since, your'e playing the compiler) could do a systematic check to find the bottom-most (lowest in the inheritance tree) overridden method someFunc() starting from class A and ending at class AA. In this search, you'll look for same method signatures as was validated in overloading resolution. This method will be the method which will be invoked.
Now, you may be wondering, "What the heck", is this search done everytime ? ... Well, Not really. The compiler knows the overhead of finding this everytime, and as such, maintains a data-structure called Virtual Table for every class type. Think of virtual table, as mapping from method signatures (which are publicly accessible) to the function pointers. This virtual table is made by compiler during compilation process and is maintained in-memory during program execution. In our example, class A and class AA will both have their own virtual tables. And when compiler has to be find someFunc() in class AA (since actual object pointed by variable a is of type AA), it will simply find the function pointer through the virtual table of Class AA. This is as simple has hashing into the table and is a constant time operation.
Regards
AViD
Adding to the Asha's answer (+1):
If you really want to understand how stuff works internally, I suggest to learn assembly and explore the generated machine code. That's what I did.
The compiler knows the types of the variables. When you use the
. or the -> operator, it looks up the symbol to the left in the
context of the class type of the right hand argument. So in
your example, it only finds A::printSomeText.
--
James Kanze

Inheritance in C++ internals

Can some one explain me how inheritance is implemented in C++ ?
Does the base class gets actually copied to that location or just refers to that location ?
What happens if a function in base class is overridden in derived class ? Does it replace it with the new function or copies it in other location in derived class memory ?
first of all you need to understand that C++ is quite different to e.g. Java, because there is no notion of a "Class" retained at runtime. All OO-features are compiled down to things which could also be achieved by plain C or assembler.
Having said this, what acutally happens is that the compiler generates kind-of a struct, whenever you use your class definition. And when you invoke a "method" on your object, actually the compiler just encodes a call to a function which resides somewhere in the generated executable.
Now, if your class inherits from another class, the compiler somehow includes the fields of the baseclass in the struct he uses for the derived class. E.g. it could place these fields at the front and place the fields corresponding to the derived class after that. Please note: you must not make any assumptions regarding the concrete memory layout the C++ compiler uses. If you do so, you're basically on your own and loose any portability.
How is the inheritance implemented? well, it depends!
if you use a normal function, then the compiler will use the concrete type he's figured out and just encode a jump to the right function.
if you use a virtual function, the compiler will generate a vtable and generate code to look up a function pointer from that vtable, depending on the run time type of the object
This distinction is very important in practice. Note, it is not true that inheritance is allways implemented through a vtable in C++ (this is a common gotcha). Only if you mark a certain member function as virtual (or have done so for the same member function in a baseclass), then you'll get a call which is directed at runtime to the right function. Because of this, a virtual function call is much slower than a non-virtual call (might be several hundered times)
Inheritance in C++ is often accomplished via the vtable. The linked Wikipedia article is a good starting point for your questions. If I went into more detail in this answer, it would essentially be a regurgitation of it.

Why can't we create objects for an abstract class in C++?

I know it is not allowed in C++, but why? What if it was allowed, what would the problems be?
Judging by your other question, it seems you don't understand how classes operate. Classes are a collection of functions which operate on data.
Functions themselves contain no memory in a class. The following class:
struct dumb_class
{
void foo(){}
void bar(){}
void baz(){}
// .. for all eternity
int i;
};
Has a size of int. No matter how many functions you have ever, this class will only take up the space it takes to operate on an int. When you call a function in this class, the compiler will pass you a pointer to the place where the data in the class is stored; this is the this pointer.
So, the function lie in memory somewhere, loaded once at the beginning of your program, and wait to be called with data to operate on.
Virtual functions are different. The C++ standard does not mandate how the behavior of the virtual functions should go about, only what that behavior should be. Typically, implementations use what's called a virtual table, or vtable for short. A vtable is a table of function pointers, which like normal functions, only get allocated once.
Take this class, and assume our implementor uses vtables:
struct base { virtual void foo(void); };
struct derived { virtual void foo(void); };
The compiler will need to make two vtables, one for base and one for derived. They will look something like this:
typedef /* some generic function pointer type */ func_ptr;
func_ptr __baseTable[] = {&base::foo};
func_ptr __derivedTable[] = {&derived::foo};
How does it use this table? When you create an instance of a class above, the compiler slips in a hidden pointer, which will point to the correct vtable. So when you say:
derived d;
base* b = &d;
b->foo();
Upon executing the last line, it goes to the correct table (__derivedTable in this case), goes to the correct index (0 in this case), and calls that function. As you can see, that will end up calling derived::foo, which is exactly what should happen.
Note, for later, this is the same as doing derived::foo(b), passing b as the this pointer.
So, when virtual methods are present, the class of the size will increase by one pointer (the pointer to the vtable.) Multiple inheritance changes this a bit, but it's mostly the same. You can get more details at C++-FAQ.
Now, to your question. I have:
struct base { virtual void foo(void) = 0; }; // notice the = 0
struct derived { virtual void foo(void); };
and base::foo has no implementation. This makes base::foo a pure abstract function. So, if I were to call it, like above:
derived d;
base* b = &d;
base::foo(b);
What behavior should we expect? Being a pure virtual method, base::foo doesn't even exist. The above code is undefined behavior, and could do anything from nothing to crashing, with anything in between. (Or worse.)
Think about what a pure abstract function represents. Remember, functions take no data, they only describe how to manipulate data. A pure abstract function says: "I want to call this method and have my data be manipulated. How you do this is up to you."
So when you say, "Well, let's call an abstract method", you're replying to the above with: "Up to me? No, you do it." to which it will reply "##^##^". It simply doesn't make sense to tell someone who's saying "do this", "no."
To answer your question directly:
"why we cannot create an object for an abstract class?"
Hopefully you see now, abstract classes only define the functionality the concrete class should be able to do. The abstract class itself is only a blue-print; you don't live in blue-prints, you live in houses that implement the blue-prints.
The problem is simply this:
what should the program do when an abstract method is called?
and even worse: what should be returned for a non-void function?
The application whould proabably have to crash or thow a runtime exception and thus this would cause trouble. You can't dummy-implement every abstract function.
A class can simply be declared abstract where it has no abstract methods. I guess that could be instantiated in theory but the class designer doesn't want you to. It may have unintended consequences.
Usually however abstract classes have abstract methods. They can't be instantiated for the simple reason that they're missing those methods.
Because logically it does not make any sense.
An abstract class is a description that is incomplete.
It indicates what things need to be filled out to make it complete but without those bits its not complete.
My first example was a chess game:
The game has lots of pieces of different type (King,Queen,Pawn ... etc).
But there are no actual objects of type piece, but all objects are instances of objects derived from piece. How can you have an object of something that is not fully defined. There is not point in creating an object of piece as the game does not know how it moves (that is the abstract part). It knows it can move but not how it does it.
Abstract classes are non-instantiable by definition. They require that there be derived, concrete classes. What else would an abstract class be if it didn't have pure virtual (unimplemented) functions?
It's the same class of question as why can't I change the value of a const variable, why can't I access private class members from other classes or why can't I override final methods.
Because that's the purpose of these keywords, to prevent you from doing so. Because the author of the code deemed doing so dangerous, undesired or simply impossible due to some abstract reasons like lack of essential functions that need to be added by specific child classes. It isn't really that you can't instantiate because a class is virtual. It's that inability to instantiate a class defines it as virtual (and if a class that can't be instantiated isn't virtual, it's an error. Same goes the other way, if instance of given class makes sense, it shouldn't be marked as virtual)
Why we cant create an object of an abstract class?
simply abstract class contains abstract methods(means the functions which are without the body) and we cannot give functionality to the abstract methods. And if we try to give functionality to the abstract methods then there will be no difference between abstract class and virtual class. So lastly if we create an object Of an abstrast class then there is no fun to call the useless functions or abstract methods as they are without the functionality..so thats why any language doesnt allow us to create an object of an abstract class..
Abstract classes instantiated would be pretty useless, because you would be seeing a lot more of "pure virtual function called". :)
It's like: we all know that a car would have 3 pedals and a steering wheel and a gear stick. Now, if that would be it, and there'd be an instance of 3 pedals and gear stick and a wheel, I'm not buying it, I want a car, like with seats, doors, AC etc. with pedals actually doing something apart from being in existence and that's what abstract class doesn't promise me, the ones implementing it do.
Basically creation of object is responsible for allocation of memory for member variables and member functions. but here, in pure virtual function we have declaration and defination in derived class.so creation of object generates error.

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

In particular, wouldn't there have to be some kind of function pointer in place anyway?
I think that the phrase "classes with virtual functions are implemented with vtables" is misleading you.
The phrase makes it sound like classes with virtual functions are implemented "in way A" and classes without virtual functions are implemented "in way B".
In reality, classes with virtual functions, in addition to being implemented as classes are, they also have a vtable. Another way to see it is that "'vtables' implement the 'virtual function' part of a class".
More details on how they both work:
All classes (with virtual or non-virtual methods) are structs. The only difference between a struct and a class in C++ is that, by default, members are public in structs and private in classes. Because of that, I'll use the term class here to refer to both structs and classes. Remember, they are almost synonyms!
Data Members
Classes are (as are structs) just blocks of contiguous memory where each member is stored in sequence. Note that some times there will be gaps between members for CPU architectural reasons, so the block can be larger than the sum of its parts.
Methods
Methods or "member functions" are an illusion. In reality, there is no such thing as a "member function". A function is always just a sequence of machine code instructions stored somewhere in memory. To make a call, the processor jumps to that position of memory and starts executing. You could say that all methods and functions are 'global', and any indication of the contrary is a convenient illusion enforced by the compiler.
Obviously, a method acts like it belongs to a specific object, so clearly there is more going on. To tie a particular call of a method (a function) to a specific object, every member method has a hidden argument that is a pointer to the object in question. The member is hidden in that you don't add it to your C++ code yourself, but there is nothing magical about it -- it's 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 knows already which method you are calling so it calls it directly.
Static methods are even simpler. They don't have a this pointer, so they are implemented exactly as you write them.
That's is! The rest is just convenient syntax sugaring: The compiler knows which class a method belongs to, so it makes sure it doesn't let you call the function without specifying which one. It also uses that knowledge to translates myItem to this->myItem when it's unambiguous to do so.
(yeah, that's right: member access in a method is always done indirectly via a pointer, even if you don't see one)
(Edit: Removed last sentence and posted separately so it can be criticized separately)
Non virtual member functions are really just a syntactic sugar as they are almost like an ordinary function but with access checking and an implicit object parameter.
struct A
{
void foo ();
void bar () const;
};
is basically the same as:
struct A
{
};
void foo (A * this);
void bar (A const * this);
The vtable is needed so that we call the right function for our specific object instance. For example, if we have:
struct A
{
virtual void foo ();
};
The implementation of 'foo' might approximate 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'
}
The virtual methods are required when you want to use polymorphism. The virtual modifier puts the method in the VMT for late binding and then at runtime is decided which method from which class is executed.
If the method is not virtual - it is decided at compile time from which class instance will it be executed.
Function pointers are used mostly for callbacks.
If a class with a virtual function is implemented with a vtable, then a class with no virtual function is implemented without a vtable.
A vtable contains the function pointers needed to dispatch a call to the appropriate method. If the method isn't virtual, the call goes to the class's known type, and no indirection is needed.
For a non-virtual method the compiler can generate a normal function invocation (e.g., CALL to a particular address with this pointer passed as a parameter) or even inline it. For a virtual function, the compiler doesn't usually know at compile time at which address to invoke the code, therefore it generates code that looks up the address in the vtable at runtime and then invokes the method. True, even for virtual functions the compiler can sometimes correctly resolve the right code at compile time (e.g., methods on local variables invoked without a pointer/reference).
(I pulled this section from my original answer so that it can be criticized separately. It is a lot more concise and to the point of your question, so in a way it's 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 pointed-to function inside the object
Why? Because it's usually a lot more efficient that way. Indirect calls are expensive instructions.
There's no need for function pointers as it cant change during the runtime.
Branches are generated directly to the compiled code for the methods; just like if you have functions that aren't in a class at all, branches are generated straight to them.
The compiler/linker links directly which methods will be invoked. No need for a vtable indirection. BTW, what does that have to do with "stack vs. heap"?