Section 1: A simple questions about virtual functions
Question requirement: Write the running result of the following program?
View plaincopy to clipboardprint?
# Include <iostream>
Using namespace std;
Class
{
Public:
Virtual void p ()
{
Cout <"A" <endl;
}
};
Class B: public
{
Public:
Virtual void p ()
{
Cout <"B" <endl;
}
};
Int main ()
{
A * a = new;
A * B = new B;
A-> p ();
B-> p ();
Delete;
Delete B;
Return 0;
}
# Include <iostream>
Using namespace std;
Class
{
Public:
Virtual void p ()
{
Cout <"A" <endl;
}
};
Class B: public
{
Public:
Virtual void p ()
{
Cout <"B" <endl;
}
};
Int main ()
{
A * a = new;
A * B = new B;
A-> p ();
B-> p ();
Delete;
Delete B;
Return 0;
}
I think this interview question should be a relatively simple question about the knowledge of virtual functions. Then, I hope that you will encounter this kind of questions about virtual functions. Whether it is difficult or easy, you will be able to draw a line from each other. Then the purpose of this chapter will be achieved. OK. Please follow my ideas and proceed step by step (the output result of the above program is a B ).
Section 2: differences between functions with or without virtual functions
1. When FUNCTION p () in the above program is not a virtual function, what is the running result of the program? The following code is used:
Class
{
Public:
Void p ()
{
Cout <"A" <endl;
}
};
Class B: public
{
Public:
Void p ()
{
Cout <"B" <endl;
}
};
Right, the program will output two A, A at this time. Why?
We know that when constructing a class object, if it has a base class, we will first construct the base class object and then construct the own object of the derived class. As shown above, A * a = new A, call the default constructor to construct the base class A object, and then call the function p (), a-> p (); Output A, which is no problem.
Then, A * B = new B; constructs the derived class object B. Because B is A derived class Object of the base class A, it first constructs the base class A object, then construct the derived class object. However, when the function in the program is called as a non-virtual function, the Class B object's call to function p () has been statically determined during compilation, no matter whether base class pointer B finally points to a base class object or a derived class object, as long as the function called by the following object is not a virtual function, it will be ignored directly, instead, call the p () function of the Base Class.
2. What if I add a virtual function? That is, what is the output result of the program like the above program?
Before that, we have to clarify the following two points:
A. When a function defined in the base class is called through a base class reference or pointer, we do not know the exact type of the object that executes the function. The object that executes the function may be of the base class type, it may also be a derived type.
B. If a non-virtual function is called, the function defined by the base class type is executed no matter what type of the actual object is (as described in the preceding 1st points ). If you call a virtual function, you cannot determine which function to call until the runtime. The running virtual function references the version of the Type Definition of the object to which the bound or Pointer Points.
Based on the above B's point of view, we know that if we add a virtual function, as shown in the above question,
Class
{
Public:
Virtual void p ()
{
Cout <"A" <endl;
}
};
Class B: public
{
Public:
Virtual void p ()
{
Cout <"B" <endl;
}
};
Int main ()
{
A * a = new;
A * B = new B;
A-> p ();
B-> p ();
Delete;
Delete B;
Return 0;
}
The output result of the program is a B.
So far, our questions have been solved. However, the problem of virtual functions has not been solved yet.
Section 3: Principles and nature of virtual functions
We already know that the general implementation model of virtual functions is: each class has a virtual table, which contains the virtual tables that are useful in this class) function address, and each object has a vptr pointing to the virtual table.
Let me cite an example from the book "Deep Exploration of c ++ object models:
Class Point {
Public:
Virtual ~ Point ();
Virtual Point & mult (float) = 0;
Float x () const {return _ x;} // non-virtual function, not stored
Virtual float y () const {return 0 ;}
Virtual float z () const {return 0 ;}
//...
Protected:
Point (float x = 0.0 );
Float _ x;
};
1. In the Point Object pt, there are two things: one is data member _ x and the other is _ vptr_Point. Where _ vptr_Point points to virtual table point, and this virtual table point stores five things, as described in the annotations in the above program: in the virtual table layout shown in the preceding figure:
Virtual ~ Point () is assigned slot 1,
Mult () will be assigned slot 2.
Y () is will be assigned slot 3
Z () will be assigned slot 4.
Class Point2d: public Point {
Public:
Point2d (float x = 0.0, float y = 0.0)
: Point (x), _ y (y ){}
~ Point2d (); // 1
// Rewrite base class virtual functions
Point2d & mult (float); // 2
Float y () const {return _ y;} // 3
Protected:
Float _ y;
};
2. In the object pt2d of Point2d, there are two things: one is data member _ y and the other is _ vptr_Point. _ Vptr_Point points to virtual table point2d. Because Point2d inherits from the Point, ~ Point2d (), Point2d & mult (float), float y () const, and Point: z () functions that have not been rewritten.
Class Point3d: public Point2d {
Public:
Point3d (float x = 0.0,
Float y = 0.0, float z = 0.0)
: Point2d (x, y), _ z (z ){}
~ Point3d ();
// Overridden base class virtual functions
Point3d & mult (float );
Float z () const {return _ z ;}
//... Other operations...
Protected:
Float _ z;
};
3. understanding can be analyzed based on the situations 1 and 2 mentioned above. OK. For more information, see.
(Figure: virtual table layout: single inheritance)