The method of member function invocation in C + + object model

Source: Internet
Author: User
Tags inheritance object model


Objective
C + + member functions are divided into static functions, non-static functions and virtual functions three kinds, in this series of articles, many mentions static and non-static does not affect the memory occupied by objects, and virtual functions need to introduce virtual pointers, so you need to adjust the memory layout of the object. Now that you have solved the problem of the layout of the data, functions, etc. in memory, the next thing to consider is how to invoke, the three functions mentioned above are different calling mechanisms, and the difference between the two is exactly what this blog needs to discuss.

Non-static member functions

One of the design guidelines for C + + is that non-static member functions must be at least as efficient as the general non-member functions. To achieve this, member properties of member functions do not add to the burden. Consider the following two function calls:


int Getage (Animal *_this);//Non member function
int animal::getage ();//member function
The Getnum function is defined as follows:
int Getage () {
return age;
}

The former needs to pass in a class pointer, which belongs to a member function call, which directly indicates the function call of the animal class. Essentially, the two functions are the same, because the compiler converts the latter to the former, and the conversion steps are as follows:

Rewrite the prototype of the function so that it accepts an extra parameter, which is the function's this pointer:

int Animal::getnum (Animal *this);//Insert a This pointer within the function

Change each access to a non-static member variable to be accessed through the this pointer:

{
return this.age;
}

To rewrite a member function as an external function, the function name is processed by "mangling" so that it is called a unique vocabulary in the program, as the above function may be handled as: GETNUM_ANIMALFV (P), where the name is guaranteed to be no conflict!
In this way, the extern "C" Operation suppresses the "mangling" effect of the function name and is used to invoke the C function in C + +.

So, the key to rewriting a member function to a non member function is two: one is the channel that can provide the function with a read-write member variable, and the other is to resolve the name conflict that may be brought. The former is well resolved by passing a this pointer, which ensures the uniqueness of the name by means of a certain name-conversion rule.

Virtual member functions

Let's think about it. If a virtual function exists in a class, the compiler does the following three things:

Assigns a virtual function table to the class that holds the virtual function at the executor's address
Insert a virtual pointer in the class to point to the virtual table of the class
The entry address of each virtual function is stored in the corresponding slot in the virtual function table.
So if you want to call a virtual function correctly, you just need to find the virtual function in the corresponding position in the virtual function table, so consider the following example.

Class animal{
Public
Char name[10];//animal Name
int weight;//Weight
virtual void Eat () {}
};
Animal *animal;
Animal->eat ();

When a virtual function eat is invoked, the compiler is automatically converted to the following code:

Vptr is a pointer to a virtual function table, eat stored in the first position of the virtual function,
Because it is a member function, the function must also pass in a this pointer parameter
(* animal->vptr[0]) (animal);


Only if the pointer and the reference can show polymorphic forms, what if we display the call or invoke it directly with the class object?

Show Call eat function
Animal::eat ();
Directly using the object to invoke the
Animal Animal;
Animal.eat ();

In both of these calls, the former suppresses the virtual mechanism and invokes the Eat () directly as a non-static member function. For the latter, suppose the compiler converts it to the following form:

1
(* animal.vptr[0]) (&animal);
This is semantically correct, but there is absolutely no need to do so, so the compiler treats it directly as a animal::eat () display call.

Virtual function calls under single inheritance

When a class inherits from a base class, the virtual functions in it can occur in the following three cases:

A virtual function in a subclass overrides the virtual function of the parent class.
A virtual function entity that inherits from the base class, which is present in the base class, is not overridden in a subclass
A pure virtual function that is used to "Occupy" a table of virtual functions or as an exception handler for an actuator
For example, in three cases, subclasses do the following when building their own virtual function tables:

When the virtual function of the parent class is overridden, the corresponding slot in the virtual function table is rewritten as the virtual function entry address of the subclass
When inheriting a virtual function instance of a base class, simply copy the instance's address to the virtual function table of the subclass
Subclasses can define their own instances of virtual functions, which are archived in the slot of virtual tables, and the dimensions of virtual tables increase
Here's a reference to an example that posting previously talked about, taking into account the following inheritance relationships:

Single inheritance

Its memory layout is as follows:

Memory layout under single inheritance
You can see that the virtual function table is rewritten in subclasses, so how do you call the virtual function for such inheritance? We can observe that the relative position of the function in the virtual function table of the parent class is unchanged in the subclass, for the following call:


void Fun (Dog *dog) {
Dog->eat ();
}
dog* Dog = new Dog ();
animal* Animal = new Dog ();

Fun (dog);//The first way to invoke a direct pass to a dog pointer
Fun (animal);//The second invocation method, passing in a animal pointer
If you are passing in an object pointer to a dog class, so directly using the method in the previous section, if you pass in an object pointer to a animal class, we can see that, as always, we can take the method in the previous section because the position of eat () in the virtual function table has not changed, The only thing that is known at the execution time is: which eat () function is invoked.

virtual function invocation under multiple inheritance

With the above understanding, we know that a virtual function invocation is nothing more than two points to meet:

Need to know the address of the virtual function table
Need to know the position of the virtual function in the virtual function table
However, in multiple inheritance, this becomes somewhat more complex, with multiple virtual tables in multiple inheritance, such as the following inheritance relationships and memory layouts:


Multiple inheritance

Its memory layout is as follows:

Memory layout under multiple inheritance

Or take the fun function above as an example, consider the following invocation methods:


Dog *dog = new Dog ();
Dog->eat ();//The first invocation method, passing directly into a dog pointer
Dog->sleep ();//The second invocation method, passing in a animal pointer
Dog->jump ();//The third invocation way, passing in a Canidae pointer


For the first two invocation methods, the invocation is basically similar to the previous section and does not need to change the this pointer because the beginning of the first bitwise inheritance class is the same as the beginning of the subclass object. For the third invocation, it seems a bit complicated. If you continue to pass in a not-adjusted this pointer, it is difficult to get Canidae's virtual table address. Here we first introduce a thunk method. The role of thunk is:

Adjust the this pointer with the appropriate offset

Jump to the corresponding virtual function

In accordance with Thunk's thought, the this pointer needs to be adjusted as follows when the jump () function is called:


Thunk
This+=sizeof (Animal);
Dog::eat (this);

Well, our problem becomes a multiple inheritance relationship, except that the first bit of the inheritance order, other bits of the class to implement virtual function calls need to make some adjustments. This adjustment occurs in the following two situations:


One, point a base class pointer to a subclass, of course, is the inheritance order after the first bit of the base class
Canidae *canidae = new Dog ();
Second, use the subclass pointer to call the base class function, of course, is the inheritance order after the first bit of the base class function
Dog Dog = new Dog ();
Dog->jump ();


In the first case, you need to adjust the Canidae pointer backward to the corresponding base class portion of the subclass sizeof (Animal) bit.
In the second case, you need to adjust the dog pointer backward sizeof (ANIMAL) bit and point to the Canidae base class section in dog.

As a result, virtual function calls under multiple inheritance are easier to understand, do you understand?

virtual function invocation under dummy inheritance

For virtual inheritance, the address of the virtual base class is stored in the memory layout for different compilers, and the book is directly like a maze. Well, I came to explore the origin of the purpose, by the author of this statement is really scared.

In virtual function calls under dummy inheritance, the complex point is still how to adjust the this pointer, and virtual inheritance has a virtual base class pointer over multiple inheritance, which makes the situation complex and changeable.

The author finally gives a definition: Do not define non-static member variables in the virtual base class, and want to be afraid these will affect the placement of the virtual base class pointer in memory, thus increasing the complexity of determining the appropriate offset.

Static member functions
The biggest difference between a static member function and the other member function is that it has no this pointer, and its main characteristics are:

It is not able to directly access Non-static member variables in its class
It cannot be declared as const, volatile, or virtual.
It does not need to be invoked through a class object
Therefore, calls to static member functions are almost equivalent to non-member function calls. Of course, in order to indicate that he is a class member function, it is necessary to add class information to the naming adjustment as follows:


Animal::getage ()//Suppose Getage is a static member function
It is named after the adjustment as follows:


GETAGE_ANIMALSFV ();//SFV indicates that he is a static member function that has a blank argument list (void)
Summarize
This blog explains the three class member function (non-static, static, virtual function) of the underlying call mechanism, and C + + for function naming, this pointer adjustment rules. We can see that C + + is on the member function call, for static, non-static member functions are basically equivalent to non-members function in the function invocation efficiency, but the virtual function calls to satisfy the polymorphism, need to adjust this pointer, find the virtual table address and so on operation, affect its function call efficiency, but these are also worth!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.