#include
using namespace std;
int main(){
class c1{
public:
int func(){
cout<<\"in the c1\";
}
When a member function is not virtual
, the function called is determined only by the type of the expression to the left of the dot (.
) or arrow (->
) operator. This is called the "static type".
When a member function is virtual
, the function called is determined by the actual most derived type of the object named by the expression left of the dot (.
) or pointed to by the expression left of the arrow (->
). This is called the "dynamic type".
Note that when a variable, member, parameter, or return type used to the left of a dot has a plain class type, the static type and dynamic type are always the same. But if a variable, member, parameter, or return type is a pointer or reference to a class type, the static type and dynamic type can be different.
It may help to see virtual and non-virtual functions implemented in C style.
struct bob {
int x;
static int get_x_1( bob* self ){ return self->x; }
int get_x_2() { return this->x; }
};
inline int get_x_3( bob* self ){ return self->x; }
all 3 of the above are basically the same thing (minor details like calling convention -- which registers or stack location arguments go on -- can differ).
Non virtual member functions are just functions that take a semi-secret pointer called this
. Semi-secret because it is right there on the left of the method name.
This is important to understand. Non-virtual calls are just fancy function calls. Instances of the class don't store pointers to its methods, or anything like that. They are just syntactic sugar for humdrum function calls.
Now virtual member functions are different.
Here is roughly how we'd implement this:
class bob{
public:
virtual int get_x(){ return x; }
int x;
};
without using virtual
:
struct bob;
using get_x=int(bob*);
struct bob_vtable {
get_x* get_x=0;
};
inline int get_x_impl( bob* self );
bob_vtable* get_bob_vtable(){
static bob_vtable vtable{ get_x_impl };
return &vtable;
}
struct bob {
bob_vtable* vtable=0;
int x;
int get_x(){ return this->vtable->get_x(this); }
bob(): vtable(get_bob_vtable()) {}
};
inline int get_x_impl( bob* self ){ return self->x; }
lots of stuff going on.
First we have get_x_impl
, which is a lot like the non-virtual get_x
s above.
Sexond, we have a table of function pointers (here dontainig just one) called a vtable. Our bob
contains a pointer to a vtable as its first entry. In it we have a function pointer pointing at our get_x_impl
. Finally, bob
has a get_x
method that forwards calls through the vtable, through the function pointer, into the get_x_impl
.
A derived type can, during construction, change the vtable pointer to point to a different table of functions, with a different implementation of get_x
.
Then when ypu have a pointer to bob
and call get_x
, it will follow the pointer in the changed vtable and call your replacement implementation.
When you create a virtual function, machinery like the above is written for you. When you inherit and override, code that replaces the parent vtable pointer with the derived is injected into the constructors of the derived type.
All of this is basically implementing what people in C could do before C++ existed. They just hid the details and wrote the glue code for you in C++.
See http://www.cs.technion.ac.il/users/yechiel/c++-faq/dyn-binding.html , And I quote:
Non-virtual member functions are resolved statically. That is, the member function is selected statically (at compile-time) based on the type of the pointer (or reference) to the object.
In contrast, virtual member functions are resolved dynamically (at run-time). That is, the member function is selected dynamically (at run-time) based on the type of the object, not the type of the pointer/reference to that object. This is called "dynamic binding." Most compilers use some variant of the following technique: if the object has one or more virtual functions, the compiler puts a hidden pointer in the object called a "virtual-pointer" or "v-pointer." This v-pointer points to a global table called the "virtual-table" or "v-table."