1 Introduction
The virtual function is a mechanism for achieving polymorphism in C . The core concept is to access the functionality defined by the base class. Suppose we have the following levels:
Class a {public: Virtual void foo () {cout << "A:: foo () is caled << endl;}};
Class B: Public a {public: Virtual void foo () {cout << "b :: foo () is caled << endl;}};
So, when you are using, we can:
A * a = new b (); A-> foo (); // Here, Although a pointer to A, the called function (foo) is B!
This example is a typical application of virtual functions. In this example, maybe you have some concepts for virtual functions. It is virtual in the so-called "delayed" or "dynamic cable", and the call of a class function is not determined at the compilation time, but is determined at runtime. Since the code is written, it cannot be determined that the function of the base class is still the function of which is the "virtual" function.
The virtual function can only reach a polymorphic effect by means of a pointer or reference, if it is the following code, although it is a virtual function, it is not a polymorphic:
Class a {public: virtual void foo ();
Class B: Public a {Virtual Void foo ();
Void bar () {a a; a.foo (); // a :: foo () called}
1.1 Polymorphism After understanding the meaning of the virtual function, it is easy to consider what is more likely. Still targeting the level of the above level, but the method used by the method is more complicated:
Void bar (a * a) {a-> foo (); // called A :: foo () or b :: foo ()? }
Because foo () is a virtual function, in this function, only according to this code, there is no way to determine that here is called A :: foo () or b :: foo (), but it can be sure: if A Pointing to an example of a class, then A :: foo () is called, if a point to the Class B instance, then b :: foo () is called.
This same code can produce different effects, known as "polymorphism".
1.2 What is the use of polymorphism? Multi-state is so magical, but what can be used? This proposition, I am difficult to use one or two sentences, the general C tutorial (or other object-oriented tutorial) use a picture example to display polymorphism purposes, I will no longer repeat this example, if you don't know This example, it should be introduced if you find this book. I tried to describe an example of an abstract angle, and then combined with the example of the drawing, maybe you are more likely to understand.
In the object-oriented programming, the data is first abstract (determined the base class) and inheritance (determined to send class), and constitute a class level. This class-level user is using them, if you still write the code for the base class when you need the base class, you will be able to write the code for the classification when you need to derive class, it is equals that the class level is completely exposed to the user. . If this class hierarchy changes (add new classes), you need to "know" (for new classes). This increases the coupling between the class level and its users, and some people are listed as one of the "Bad Smell" in the program. Polymorphisms can make programmers from this dilemma. Take a look at the example of 1.1, bar () as a class-level user of AB, it doesn't know how many classes in this class level, every class is called, but it can work well, when After a C class is born from the A class, BAR () does not need to "know" (modify). This is completely attributed to the polymorphic-compiler to generate code that can determine the modified function at runtime.
1.3 How to "Dynamic Board" compiler How to generate the code that is called function for the virtual function to determine the code of the modified function? That is, how is the virtual function actually processed by the compiler? Lippman speaking several ways in depth exploration of the different chapters in the C object model [1], here is the "standard" method briefly introduces it.
What I said "Standard" is the so-called "vTable" mechanism. The compiler found a function that is declared as Virtual in a class, which will make a virtual function table, which is VTABLE. VTable is actually an array of function pointers, each virtual function, which takes up a slot of this array. A class has only one vTable, regardless of how many instances it. Detecting classes have their own vTable, but the VTABLE of the derived class has the same functionality in the same function as the base class, and the virtual function of the same name is placed in the same location of the two arrays. When you create a class instance, the compiler also adds a VPTR field in the memory layout of each instance, which points to the VTABLE of this class. Through these means, the compiler will rewrite this call when seeing a virtual function call, for the example in 1.1:
Void Bar (a * a) {a-> foo ();
Will be rewritten as:
Void Bar (A * a) {(A-> VPTR [1]) ();
Because the Foo () function of the derived class and base class has the same vTable index, their VPTR points to different VTABLE, so that the way to be determined in the runtime, which FOO () function can be determined in the runtime.
Although the actual situation is far less simple, the basic principle is rough.
1.4 OverLoad and Override virtual functions are always rewritten in the derived class, which is called "override". I often confuse two words "Overload" and "Override". But with more and more books of various C , the later programmers may not commit the mistake I have committed. But I plan to clarify:
OVERRIDE is a virtual function that assigns a base class to rewrite the base class, which is like a FOO () function in the Class A in our front B class. The rewritten function must have a consistent parameter table and return value (the C standard allows the return value to the case, this I will introduce some of the "Syntax" section, but few compilers support this feature). This word seems to have no suitable Chinese words, and some people are translated into "coverage" and is also appropriate. The OverLoad appointment is translated into "overload". It means that a function of writing a different function with the existing function but the parameter table. For example, a function can accept an integer as a parameter, or the floating point number can be accepted as a parameter. 2. The symbol of the syntax virtual function of the virtual function is the "Virtual" keyword. 2.1 Use the Virtual keyword to consider the following class level:
Class a {public: virtual void foo ();
Class B: Public a {public: void foo (); // No virtual keyword!};
Class C: public b // Inherits from B, not inheriting from A! {public: void foo (); // no virtual keyword! }
In this case, B :: foo () is a virtual function, C :: foo () is also virtual function. Therefore, it can be said that the base class declands the virtual function, in the derived class is also a virtual function, even if the Virtual keyword is no longer used.
2.2 Pure virtual functions The following statement indicates that a function is a pure virtual function:
Class a {public: Virtual void foo () = 0; // = 0 flags a virtual function is a pure virtual function};
After a function declares is pure, the pure virtual function means: I am an abstract class! Don't install me! The pure virtual function is used to standardize the behavior of derived classes. It is actually the so-called "interface". It tells the user, and my derived class will have this function.
2.3 The false argument function of the function can be virtual, even pure. E.g:
Class a {public: Virtual ~ a () = 0; // Pure Pattern Function};
When a class is intended to be used as a base class of other classes, its destructor must be virtual. Consider the following example:
Class a {public: a () {ptra_ = new char [10];} ~ a () {delete [] PTRA_;} // non-false argument function private: char * ptra_;};
Class B: Public a {public: b () {ptrb_ = new char [20];} ~ b () {delete [] PTRB_;} private: char * ptrb_;};
Void foo () {a * a = new b; delete a;}
In this example, the program may not run like you imagine, when executing Delete A, actually only A :: ~ a () is called, and the secting function of the Class B is not called! Is this terrible?
If you will be changed to Virtual, you can guarantee that B :: ~ b () is also called when Delete A is. Therefore, the sectors of the base class must be Virtual.
There is no role in the destructor of pure virtuality, it is a virtual. Usually only when you want to turn a class into an abstract class (categories that cannot be instantiated), and this class does not have the right function can be purely ficted, you can use the pure destructor to achieve the purpose.
2.4 fictional creation function? The constructor cannot be empty. 3. Virtual function uses skills 3.1 Private virtual functions Consider the following example:
Class a {public: void foo () {bar ();} private: virtual void bar () {...}};
Class B: Public a {private: Virtual void bar () {...}};
In this example, although BAR () is private in the Class A, it can still occur in the derived class and can still produce polymorphic effects as the virtual function of public or protected. It doesn't matter because it is private, A :: foo () does not access the case of :: bar (), and does not happen to Override in A :: Bar (). Case.
The language of this way is: a tells B, you'd like the Override my bar () function, but you don't want to use it, don't call this function yourself.
3.2 Since the virtual function in the constructor and the destructuring function calls a class of virtual functions to be called in its own constructor and the destructor, they become a normal function, not "virtual". That is to say, you cannot make yourself "polymorphism" in the constructor and the destructor. E.g:
Class a {public: a () {foo ();} // here, no matter how all A :: foo () is called! ~ A () {foo ();} // with Virtual void foo ();
Class B: Public a {public: Virtual void foo ();
Void bar () {a * a = new b; delete a;}
If you want Delete a, it will cause b :: foo () to be called, then you are wrong. Similarly, when New B, a constructor is called, but in the constructor of A, it is called A :: foo () instead of B:: foo ().
3.3 Multi-inheritance 3.4 When is the virtual function to design a base class, if you find a function, you need a different performance in the derived class, then it should be virtual. From the perspective of design, the virtual function in the base class is the interface, and the virtual function in the derived class is the specific implementation of the interface. In this way, the behavior of the object can be abstracted.
Take the design mode [2] as an example, Creator's factoryMethod () is a virtual function, after derived class Override function, generates a different Product class, which is used by the produced Product () function () function. The base class of the base class is operated for the Product class, and of course the Product class must also have multiple (virtual functions).
Another example is a collection operation, assuming that you have a class hierarchy with a class A class, and use a std :: vector to save this class level of different instance pointers, then you must hope When operating the class in this collection, don't return each pointer back to its original type (derived class), but want to do the same operation. Then you should declare this "the same operation" as Virtual.
In reality, there are not only the two examples of me, but big principles are what I said earlier "If a function needs to have different performances in the derived class, then it should be virtual." This sentence can also be said in turn: "If you find that the base class provides virtual functions, then you'd better Override it." 4. Reference information [1] Depth exploration C object model, Stanley B.Lippman, Houjie
[2] Design Patterns, Elements of Reusable Object-Oriented Software, Gof