C + + multi-state virtual Table Analysis diagram __c++

Source: Internet
Author: User

polymorphic

The concept of polymorphism is a little blurry, and if you want to describe it in a clear language at the outset so that the reader can understand it, it doesn't seem realistic, so let's look at the following code:

Routine 1
#include <iostream>
using namespace Std;

Class Vehicle
{
Public
Vehicle (float speed,int total)
{
Vehicle::speed=speed;
Vehicle::total=total;
}
void Showmember ()
{
cout<<speed<< "|" <<total<<endl;
}
Protected
float speed;
int total;
};
Class Car:public Vehicle
{
Public
Car (int aird,float speed,int total): Vehicle (Speed,total)
{
Car::aird=aird;
}
void Showmember ()

{
cout<<speed<< "|" <<total<< "|" <<aird<<endl;
}
Protected
int Aird;
};

void Main ()
{
Vehicle A (120,4);
A.showmember ();
Car B (180,110,4);
B.showmember ();
Cin.get ();
}

In C + + is to allow a derived class to overload the base class member function, for the overload of the class, the explicit, not homogeneous object, call its class member function, the system is know how to find its class members with the same name, the above code in the A. Showmember (), that is, the call is Vehicle::showmember (), B.showmember (), which is called car::showmemeber ();.

However, in the actual work, it is likely to encounter the object belongs to the class is not clear, let's look at the derived class members as a function of the parameters passed by example, the code is as follows:

Routine 2
#include <iostream>
using namespace Std;

Class Vehicle
{
Public
Vehicle (float speed,int total)
{
Vehicle::speed=speed;
Vehicle::total=total;
}
void Showmember ()
{
cout<<speed<< "|" <<total<<endl;
}
Protected
float speed;
int total;
};
Class Car:public Vehicle
{
Public
Car (int aird,float speed,int total): Vehicle (Speed,total)
{
Car::aird=aird;
}
void Showmember ()
{
cout<<speed<< "|" <<total<< "|" <<aird<<endl;
}
Protected
int Aird;
};

void Test (Vehicle &temp)
{
Temp. Showmember ();
}

void Main ()
{
Vehicle A (120,4);
Car B (180,110,4);
Test (a);
Test (b);
Cin.get ();
}

In the example, object A and B are the objects of the base class and the derived class, while the parameter of the function test is only a reference to the vehicle class, and the system regards the car class object as a vehicle class object because the cover range of the car class contains the vehicle class, according to the class inheritance. So the definition of the test function is not wrong, we want to use the test function to achieve the purpose is to pass the reference of different classes of objects, different classes, overloaded, Showmember member functions, but the results of the operation of the program is unexpected, The system is not sure whether the base class object or derived class object passed over is a Showmember member function of the base class, either as a base class object or as a derived class object.

In order to solve the above problem of not correctly resolving the object type, C + + provides a technique called polymorphism (polymorphism) to solve the problem, and for example program 1, this ability to determine at compile time which overloaded member function is invoked is called Advance early binding, and the ability of the system at runtime to determine which overloaded member function is invoked based on its type, called polymorphism , or a hysteresis binder (late binding), Here we will look at the routine 3, is the lag of the joint, hysteresis is the way to solve the problem of polymorphism.

The code is as follows:

Routine 3
#include <iostream>
using namespace Std;

Class Vehicle
{
Public
Vehicle (float speed,int total)
{
Vehicle::speed = speed;
Vehicle::total = total;
}
virtual void Showmember ()//virtual function
{
cout<<speed<< "|" <<total<<endl;
}
Protected
float speed;
int total;
};
Class Car:public Vehicle
{
Public
Car (int aird,float speed,int total): Vehicle (Speed,total)
{
Car::aird = Aird;
}
virtual void Showmember ()//virtual function, in a derived class, because of the inherited relationship, the virtual can also not add
{
cout<<speed<< "|" <<total<< "|" <<aird<<endl;
}
Public
int Aird;
};

void Test (Vehicle &temp)
{
Temp. Showmember ();
}

int main ()
{
Vehicle A (120,4);
Car B (180,110,4);
Test (a);
Test (b);
Cin.get ();
}

When the function of the polymorphic function relies on the definition of the virtual functions, and when the overloaded member function of the polymorphic problem needs to be solved, and the virtual keyword is added, then the member functions become virtual functions, from the result of the example code running, the system can successfully distinguish the true type of the object. The respective overloaded member functions were successfully invoked.

Polymorphism features allow programmers to save the details of the consideration, improve the development efficiency, so that the code greatly simplified, of course, the definition of virtual function is also flawed, because the polymorphic features increased some data storage and execution of instructions overhead, so it is best not to use polymorphism.

The definition of a virtual function follows the following important rules:

1. If a virtual function appears in the base class and in a derived class, but only if the name is the same, and the formal parameters are different, or the return type is different, then even if the virtual keyword is added, there is no lag associated.

2. Only a member function of a class can be described as a virtual function, because a virtual function is only suitable for use with a class object that has an inheritance relationship, so a normal function cannot be described as a virtual function.

3. Static member functions cannot be virtual functions, because static member functions are characterized by being unrestricted to an object.

4. An inline (inline) function cannot be a virtual function because an inline function cannot dynamically determine a position in the runtime. Even though the virtual function is defined inside the class, the system still sees it as not inline at compile time.

5. Constructors can not be virtual functions, because when the construction, the object is still a bit of space, only when the construction is complete, the object is the concrete class instance.

6. Destructors can be virtual functions and are often known as virtual functions.


To illustrate, although we say that using virtual functions can reduce efficiency, but it's always good to define all the member functions in a class as virtual at a faster processor speed today, and it's no harm in addition to adding some extra overhead, and it's good for the encapsulation features of the class.

For the important rule 6 used on the above virtual function, it is necessary to illustrate why the destructor of a class with polymorphic properties is necessary to declare virtual.

The code is as follows:

#include <iostream>
using namespace Std;

Class Vehicle
{
Public
Vehicle (float speed,int total)
{
Vehicle::speed=speed;
Vehicle::total=total;
}
virtual void Showmember ()
{
cout<<speed<< "|" <<total<<endl;
}
Virtual ~vehicle ()
{
cout<< "Load vehicle base class destructor" <<endl;
Cin.get ();
}
Protected
float speed;
int total;
};
Class Car:public Vehicle
{
Public
Car (int aird,float speed,int total): Vehicle (Speed,total)
{
Car::aird=aird;
}
virtual void Showmember ()
{
cout<<speed<< "|" <<total<< "|" <<aird<<endl;
}
Virtual ~car ()
{
cout<< "load car derived class destructor" <<endl;
Cin.get ();
}
Protected
int Aird;
};

void Test (Vehicle &temp)
{
Temp. Showmember ();
}
void Delpn (Vehicle *temp)
{
Delete temp;
}
void Main ()
{
Car *a=new car (100,1,1);
A->showmember ();
DELPN (a);
Cin.get ();
}

From the running result of the example code above, when calling DELPN (a); later, in the destructor, the system succeeds in determining the destructor of the car class, and if the virtual modification of the destructor is removed and the results are observed, the destructor of the base class is always invoked. From this we find that the virtual modification of polymorphic properties is not only necessary for the normal member functions of base classes and derived classes, but also for destructors of base classes and derived classes.

Detailed virtual table

The function of virtual function in C + + is mainly to realize the mechanism of polymorphism. About polymorphism, in short, is to use the pointer of the parent type to an instance of its subclass, and then call the member function of the actual subclass through the pointer to the parent class. This technique allows the pointer of the parent class to have "multiple forms," which is a generic technique. The so-called generic technology, plainly is to try to use immutable code to implement the variable algorithm. For example: template technology, RTTI technology, virtual function technology, or try to do at compile-time resolution, or try to do run-time resolution.

On the use of virtual functions, I do not do too much elaboration here. You can take a look at the relevant C + + books. In this article, I just want to from the virtual function of the implementation mechanism for everyone a clear analysis.

Of course, the same article on the internet also appeared some, but I always feel that these articles are not very easy to read, large sections of code, no pictures, no detailed instructions, no comparison, no extrapolate. Not conducive to learning and reading, so this is the reason I want to write this article. I also hope that members will give me more advice.

Let's go to the world of virtual functions together.

virtual function Table

People who know C + + should know that virtual functions (virtual function) are implemented by a virtual function table (virtual table). Referred to as v-table. In this table, is mainly a class of virtual functions of the Address table, this table solves the problem of inheritance, coverage, to ensure that the real response to the actual function. Thus, in an instance of a class with a virtual function, the table is allocated to the memory of the instance. So, when we manipulate a subclass with a pointer to a parent class, the virtual function table is important, and it is like a map that indicates the function that is actually supposed to be called.

Here we look at this virtual function table. In the C + + standard specification, the compiler must ensure that the pointer to the virtual function table exists at the very beginning of the object instance (this is to ensure that the offset of the virtual function is correctly fetched). This means that we get the virtual function table through the address of the object instance, and then we can iterate through the function pointer and call the corresponding function.

Listen to me so much, I can feel that you may be more disoriented now than before. No problem, the following is a practical example, I believe that the smart you see it.

Let's say we have a class like this:

Class Base {

Public

virtual void F () {cout << "base::f" << Endl;}

virtual void g () {cout << "base::g" << Endl;}

virtual void H () {cout << "base::h" << Endl;}

};

According to the above, we can get the virtual function table through the example of base. The following is the actual routine:

typedef void (*fun) (void);

Base b;

Fun pfun = NULL;

cout << "virtual function table Address:" << (int*) (&b) << Endl;

cout << "virtual function table-First function address:" << (int*) * (int*) (&b) << Endl;

Invoke the

Pfun = (Fun) * (int*) * (int*) (&b));

Pfun ();

The actual operating results are as follows: (Windows xp+vs2003, Linux 2.6.22 + GCC 4.1.3)

virtual function table Address: 0012FED4

virtual function table-First function address: 0044f148

Base::f

With this example, we can see that we can get the address of the virtual function table by forcing the &b into int *, and then we can take the address of the first virtual function again, that is base::f (), which is validated in the above program (Put int* Force to a function pointer). With this example, we can see that if you want to invoke Base::g () and Base::h (), the code is as follows:

(Fun) * ((int*) * (int*) (&b) +0); Base::f ()

(Fun) * ((int*) * (int*) (&b) +1); Base::g ()

(Fun) * ((int*) * (int*) (&b) +2); Base::h ()



Note: In the above diagram, I add a node to the end of the virtual function table, which is the ending node of the virtual function table, just like the Terminator "/0" of the string, which flags the end of the virtual function table. The value of this ending flag is different under different compilers. Under Winxp+vs2003, this value is null. and under Ubuntu 7.10 + Linux 2.6.22 + GCC 4.1.3, this value is 1, which means that there is also the next virtual function table, and if the value is 0, the last virtual function table is represented.

Below, I will explain the appearance of the virtual function table in "No overlay" and "overwrite" respectively. It is meaningless not to overwrite the virtual function of the parent class. The main purpose of my story about not covering is to give a comparison. In comparison, we can know more clearly the specific implementation within it.

General Inheritance (no virtual function overrides)

Next, let's look at what the virtual function table is like when inheriting. Suppose you have an inheritance relationship as shown below:



Note that in this inheritance relationship, subclasses do not have functions that overload any of the parent classes. Then, in an instance of a derived class, its virtual function table looks like this:

For example: derive D; The virtual function table is as follows:

We can see the following points:

1 virtual functions are placed in the table in the order in which they are declared.

2 The virtual function of the parent class is in front of the virtual function of the subclass.

I believe that smart you can certainly refer to the previous program, to write a program to verify.

General inheritance (with virtual function overrides)

It is obvious that the virtual function of the parent class is overridden, otherwise the virtual function becomes meaningless. Next, let's take a look at what it would look like if a virtual function in a subclass overloaded the virtual function of the parent class. Suppose we have one of these inheritance relationships.

In order for you to see the effect of being inherited, in the design of this class, I covered only one function of the parent class: F (). Then, for an instance of a derived class, its virtual function table would look something like the following:

We can see the following points from the table,

1 the covering F () function is placed in the position of the original parent virtual function in the virtual table.

2 functions that are not covered are still.

In this way, we can see that for programs like the following,

Base *b = new Derive ();

B->f ();

The position of the F () of the virtual function table in the memory of B is already replaced by the Derive::f () function address, so the derive::f () is invoked when the actual call occurs. This enables polymorphism.

(It turns out to be such a thing ...) Note that the corresponding function is substituted instead of the overridden function being placed in the first position.

Simple and simple MFC:
1. Each class that contains a virtual function, the compiler makes a table for it, and each element in the table points to the address of a virtual function.
In addition, the compiler will of course add a member function to the class table, a pointer to the virtual function table (often referred to as vptr), and each class derived from this class has such a vptr.
2. Virtual table and this type of indirect call. The content of the virtual table is filled in with the function pointer based on the order of the virtual function declaration in the category. A derived class inherits the underlying category's virtual table (and all other members that can be inherited). When we overwrite a virtual function in a derived class, the virtual table is affected; The function address that the element in the table refers to is no longer the function address of the base class, but the function address of the derived class.

Of course, all that is said is that the derived class inherits the base class's virtual table (specifically, it cannot be said to inherit the virtual table, but some of the base class virtual table, in the middle of the derived class have, and the derived classes their own virtual functions are extended), but this is in the VC environment or the result of the VS environment, for the compiler does not work the same way , it may not inherit if it is g++. such as: http://zhidao.baidu.com/question/129641932.html

Multiple inheritance (no virtual function overrides)

Next, let's look at the situation in multiple inheritance, assuming that there is an inheritance relationship for the following class. Note: Subclasses do not have functions that overwrite the parent class.

For a virtual function table in a subclass instance, the following looks like this:

We can see:

1 each parent class has its own virtual table.

2 The member function of the subclass is placed in the table of the first parent class. (The so-called first parent class is judged in the Order of Declaration)

This is done in order to solve the different parent class type of pointer to the same subclass instance, and can call to the actual function.

multiple inheritance (with virtual function overrides)

Let's take a look at the case where a virtual function overlay occurs.

In the following illustration, we overwrite the F () function of the parent class in the subclass.

The following is a diagram of a virtual function table in a subclass instance:

We can see that the position of F () in the three parent class virtual function table is replaced by the function pointer of the subclass. In this way, we can point to a subclass of the parent class of any static type and call the subclass's F (). Such as:

Derive D;

Base1 *B1 = &d;

Base2 *b2 = &d;

Base3 *b3 = &d;

B1->f (); Derive::f ()

B2->f (); Derive::f ()

B3->f (); Derive::f ()

B1->g (); Base1::g ()

B2->g (); Base2::g ()

B3->g (); Base3::g ()

Security

Every time you write a C + + article, you always have to criticize C + +. This article is no exception. Through the above, I believe we have a more detailed understanding of the virtual function table. Water may carry a boat, and it can also overturn. Now, let's see if we can do something bad with a virtual function table.

one, accessing a subclass's own virtual function through a pointer to a parent type

We know that it is meaningless for subclasses not to overload the virtual functions of the parent class. Because polymorphism is also based on a function overload. Although in the above diagram we can see that there are derive virtual functions in the BASE1 virtual table, we simply cannot use the following statement to invoke the subclass's own virtual function:

Base1 *b1 = new Derive ();

B1->F1 (); Compilation error

Any attempt to use a parent class pointer to invoke a member function in a subclass that does not overwrite the parent class is considered illegal by the compiler, so that such a program cannot be compiled at all. But at run time, we can access the virtual function table through the way of pointer to violate C + + semantics behavior.

Second, the virtual function of accessing Non-public

In addition, if the virtual functions of the parent class are private or protected, but these are not public virtual functions will also exist in the virtual function table, so we can also access the virtual function table to access these non-public virtual functions, this is very easy to do.

Such as:

Class Base {

Private

virtual void F () {cout << "base::f" << Endl;}

};

Class Derive:public base{

};

typedef void (*fun) (void);

void Main () {

Derive D;

Fun Pfun = (Fun) * ((int*) * (int*) (&d) +0);

Pfun ();

}

Concluding remarks

C + + This language is a magic language, for programmers, we never seem to understand what the language behind us. To be familiar with the language, we need to understand the things in C + + and need to understand the dangerous things in C + +. Otherwise, it is a programming language that moves a stone to its own feet.

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.