C ++ pure virtual function virtual = 0
Reference: http://hi.baidu.com/cunlin/blog/item/d82b160102e0e4037aec2ccb.html (Baidu space)
========================================================== ======================================
Pure virtual functions in C ++
A function declaration in C ++ is called a pure virtual function. Its declaration format is as follows: Class cshape {public: Virtual void show () = 0 ;}; Pay attention to the red part. Add" = 0 "In this way, a pure virtual function is declared. Under what circumstances does the pure virtual function (pure vitrual function) be used )? 1. If you want to abstract a method in the base class, and the base class can only be inherited, but cannot be instantiated; 2, this method must be in the derived class (derived class) if the above two points are met, you can consider declaring this method as pure virtual function. for example, we first define a shape class (cshape), but all shapes require that they display themselves. So we defined a class as follows: Class cshape {virtual void show () {} ;}; But there is no cshape, so we don't want the cshape class to be instantiated. The first thing we think of is to delete the definition (Implementation) part of the show function as follows: class cshape {virtual void show () ;}; when we use the following statement to instantiate a cshape: cshape Cs; // This is not allowed, but we only use the above Code Yes, it can be compiled (but link fails ). How can we avoid a cshape being instantiated and discovered during compilation? The answer is: use pure virtual funcion. we modify the cshape class again as follows: Class cshape {public: Virtual void show () = 0 ;}; When instantiating cshape, the following error message is displayed: Error c2259: 'cshap': cannot instantiate abstract class due to following Members: Warning c00009: 'void _ thiscall cshape:: Show (void) ': pure virtual function was not defined. Let's take a look at the inherited situation. We need a cpoint2d class that inherits from cshape. it must implement the show () method in the base class (cshape. In fact, the original intention is to implement the show () method for every class derived from cshape, but we often forget to implement show () in a derived class (), to avoid this situation, pure virtual funcion plays a role. Let's take a look at the following code: Class cpoint2d: Public cshape
{
Public:
Cpoint2d ()
{
Printf ("cpoint2d Ctor is invoked/N ");
};
Void MSG ()
{
Printf ("cpoint2d. MSG () is invoked/N ");
};/* --- I'm sorry to forget implement the show ()---
Void show ()
{
Printf ("show () from cpoint2d/N ");
};------------------------------------------------*/
}; When we instantiate cpoint2d, the following error occurs during compilation: Error c2259: 'cshap': cannot instantiate abstract class due to following members: warning c00009: 'void _ thiscall cshape: Show (void) ': pure virtual function was not defined. We prevent forgetting to implement the base class method in the derived class. Maybe compiler will say: Hum! If the show method is not implemented in a derived class, I will not allow you to pass the compilation. // -------------------------------------------------------- // Now, show the completed Code, // platform: WINXP + vc6.0 // -------------- # include <iostream>
# Include <stdio. h>
Using namespace STD; Class cshape
{
Public:
Virtual void show () = 0;
};
Class cpoint2d: Public cshape
{
Public:
Void MSG ()
{
Printf ("cpoint2d. MSG () is invoked/N ");
};
/* --- I'm sorry to forget Implementation of the show ()---*/
Void show ()
{
Printf ("show () from cpoint2d/N ");
};
/*------------------------------------------------------*/
};
Void main ()
{
Cpoint2d P2D; // If the derived class (cpoint2d) does not implement show (), the compilation fails.
P2D. MSG ();
//
Cshape * pshape = & P2D;
Pshape-> show (); // The base class cannot be instantiated.
// Cshape Cs;
}
========================================================== ======================================
Virtual functions in C ++)
1. Introduction
Virtual functions are used in C ++ to implement polymorphism. The core concept is to access the functions defined by the derived class through the base class. Suppose we have the following class layers:
Class
{
Public:
Virtual void Foo () {cout <"A: Foo () is called" <Endl ;}
};
Class B: public
{
Public:
Virtual void Foo () {cout <"B: Foo () is called" <Endl ;}
};
In this case, we can:
A * A = new B ();
A-> Foo (); // here, although a points to a, the called function (FOO) is B!
This example is a typical application of virtual functions. Through this example, you may have some concepts about virtual functions. It is virtual on the so-called "Deferred Association" or "Dynamic Association". The call of a class function is not determined at the time of compilation, it is determined at the runtime. When writing the code, it cannot be determined whether the base class function or the derived class function is called, so it becomes a "virtual" function.
A virtual function can achieve polymorphism only by means of pointers or references. If the following code is used, it is a virtual function, but it is not a polymorphism:
Class
{
Public:
Virtual void Foo ();
};
Class B: public
{
Virtual void Foo ();
};
Void bar ()
{
A;
A. Foo (); // A: Foo () is called.
}
1.1 Polymorphism
After understanding the meaning of a virtual function, it is easy to consider what is polymorphism. The above class hierarchy is still targeted, but the method used is more complicated:
Void bar (A *)
{
A-> Foo (); // is a: Foo () or B: Foo () called ()?
}
Because Foo () is a virtual function, in bar function, you can only use this code to determine whether a: Foo () or B: is called here :: foo (), but it is certain that if a points to an instance of Class A, A: Foo () is called. If a points to an instance of Class B, then B: Foo () is called.
This same code can produce different effects, known as "polymorphism ".
1.2 What is the use of polymorphism?
Polymorphism is amazing, but what can it do? This proposition is hard to be summarized in one or two sentences. The General C ++ tutorial (or other object-oriented language tutorial) uses a drawing example to demonstrate the usage of polymorphism, I will not repeat this example again. If you do not know this example, you should introduce it in any book. I try to describe from an abstract point of view, and then look back at the example of the drawing, maybe it is easier for you to understand.
In object-oriented programming, data is first abstracted (determining the base class) and inherited (determining the derived class) to form a class hierarchy. When users of this class hierarchy use them, if they still need to write code for the base class when they need the base class, write the code for the derived class when they need the derived class, it means that the class level is completely exposed to the user. If there is any change in the class hierarchy (new classes are added), the user needs to "know" (write code for the new class ). In this way, the coupling between the class hierarchy and its users is increased. Someone lists this caseProgram"Bad smell" in.
Polymorphism can free programmers from this dilemma. Let's look back at the example in 1.1, bar () as the user of the A-B class hierarchy, It doesn't know how many classes there are in this class hierarchy, what each class is called, but the same can work well. When a class C is derived from Class A, bar () does not need to be "known" (modified ). This is entirely due to polymorphism-the compiler generates code for a virtual function that can be called at runtime.
1.3 "Dynamic Association"
How does the compiler determine the code of the called function when the virtual function is generated? That is to say, how is a virtual function actually processed by the compiler? In the deep exploration of the C ++ object model [1], Lippman describes several methods. Here we will briefly introduce the "standard" method.
I am talking about the "standard" method, that is, the so-called "vtable" mechanism. When the compiler finds a function declared as virtual in a class, it creates a virtual function table, that is, vtable. Vtable is actually an array of function pointers. Each virtual function occupies a slot of this array. A class has only one vtable, no matter how many instances it has. The derived class has its own vtable, but the vtable of the derived class has the same function arrangement sequence as the vtable of the base class. virtual functions with the same name are placed in the same position of two arrays. When creating a class instance, the compiler adds a vptr field to the memory layout of each instance. This field points to the vtable of the class. Through these methods, the compiler will rewrite this call when it sees a virtual function call. For example in 1.1:
Void bar (A *)
{
A-> Foo ();
}
Will be rewritten:
Void bar (A *)
{
(A-> vptr [1]) ();
}
Because the derived class and the Foo () function of the base class have the same vtable index, and their vptr points to different vtables, this method can be used to determine which Foo () to call at runtime () function.
Although the actual situation is far from that simple, the basic principle is roughly the same.
1.4 overload and override
Virtual functions are always rewritten in the derived class, which is called "Override ". I often confuse the words "overload" and "Override. But with the increasing number of C ++ books, later programmers may not make any mistakes I have made. But I want to clarify:
Override refers to the virtual function used by the derived class to override the base class, just as the Foo () function in Class A is rewritten in Class B. The rewritten function must have the same parameter table and return value (the C ++ standard allows different return values. I will briefly introduce this in the "Syntax" section, but few compilers support this feature ). It seems that there is no proper Chinese vocabulary for this word. Some people translate it into "Overwrite", which is more appropriate.
Overload conventions are translated as "heavy load ". Compile a function with the same name as an existing function but different from the parameter table. For example, a function can take an integer as a parameter or a floating point as a parameter.
2. Syntax of virtual functions
The sign of the virtual function is the "virtual" keyword.
2.1 use virtual keywords
Consider the following class levels:
Class
{
Public:
Virtual void Foo ();
};
Class B: public
{
Public:
Void Foo (); // No virtual keyword!
};
Class C: Public B // inherit from B, not from!
{
Public:
Void Foo (); // There is no virtual keyword!
};
In this case, B: Foo () is a virtual function, and C: Foo () is also a virtual function. Therefore, it can be said that the virtual function declared by the base class is also a virtual function in the derived class, 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
{
Public:
Virtual void Foo () = 0; // = 0 indicates that a virtual function is a pure virtual function.
};
After a function is declared as pure virtual, the pure virtual function means: I am an abstract class! Don't instantiate me! Pure virtual functions are used to regulate the behavior of derived classes. They are actually called "interfaces ". It tells the user that my Derived classes will all have this function.
2.3 virtual destructor
Destructor can also be virtual, or even pure virtual. For example:
Class
{
Public:
Virtual ~ A () = 0; // pure virtual destructor
};
When a class is intended to be used as the basis class of other classes, its destructor must be virtual. Consider the following example:
Class
{
Public:
A () {ptra _ = new char [10];}
~ A () {Delete [] ptra _;} // non-virtual destructor
PRIVATE:
Char * ptra _;
};
Class B: public
{
Public:
B () {ptrb _ = new char [20];}
~ B () {Delete [] ptrb _;}
PRIVATE:
Char * ptrb _;
};
Void Foo ()
{
A * A = new B;
Delete;
}
In this example, the program may not run as you think. When executing Delete A, there is actually only ::~ A () is called, and Class B's destructor are not called! Is it a little scary?
If the above ::~ Change a () to virtual to ensure that B ::~ B () is also called during Delete. Therefore, the destructor of the base class must be virtual.
Pure virtual destructor have no function, but virtual ones are enough. Generally, when you want to change a class to an abstract class (a class that cannot be instantiated), and this class does not have a suitable function that can be purely virtualized, you can use pure virtual destructor to achieve the goal.
2.4 virtual constructor?
Constructors cannot be virtual.
3. Tips for using virtual functions 3.1 private virtual functions
Consider the following example:
Class
{
Public:
Void Foo () {bar ();}
PRIVATE:
Virtual void bar (){...}
};
Class B: public
{
PRIVATE:
Virtual void bar (){...}
};
In this example, although bar () is private in Class A, it can still appear in the derived class, it can still produce the same polymorphism effect as the public or protected virtual functions. It is not because it is private, so a: Foo () cannot access B: bar (), or B: bar () to :: bar () override does not work.
The syntax is as follows: a tells B that you 'd better override my bar () function, but do not care how it is used or call this function by yourself.
3.2 call of virtual functions in constructor and destructor
When a class's virtual functions are called in its own constructor and destructor, they become common functions. That is to say, you cannot make yourself "polymorphism" in constructor and destructor ". For example:
Class
{
Public:
A () {Foo () ;}// in any case, a: Foo () is called!
~ A () {Foo ();} // same as above
Virtual void Foo ();
};
Class B: public
{
Public:
Virtual void Foo ();
};
Void bar ()
{
A * A = new B;
Delete;
}
If you want to delete a, it will cause B: Foo () to be called, then you will be wrong. Similarly, in the case of new B, the constructor of A is called, but in the constructor of A, A: Foo () instead of B :: foo ().
3.3 More inherited virtual functions 3.4 when to use virtual functions
When you design a base class, if you find that a function needs to behave differently in a derived class, it should be virtual. From the design perspective, the virtual functions that appear in the base class are interfaces, and the virtual functions that appear in the derived class are the specific implementation of interfaces. In this way, the behavior of objects can be abstracted.
Take the factory method mode in design mode [2] as an example. The factorymethod () of the Creator is a virtual function. After the override function of the derived class is used, different product classes are generated, the generated product class is used by the anoperation () function of the base class. The anoperation () function of the base class operates on the product class. Of course, the product class must also have polymorphism (virtual function ).
Another example is a set operation. Suppose you have a class hierarchy based on class A, and another STD :: vector <A *> to save the instance pointers of different classes in this class hierarchy, So you certainly want to perform operations on the classes in this set, instead of returning each pointer to its original type (derived class), you want to perform the same operation on them. Then we should declare this "same operation" as virtual.
In reality, it is far more than the two examples I mentioned, but the big principle is that I mentioned earlier: "If a function needs to have different performances in a derived class, then it should be virtual ". This sentence can also be reversed: "If you find that the base class provides virtual functions, you 'd better override it ".
4. References
[1] in-depth exploration of the C ++ object model, Stanley B. Lippman, Hou jietranslated
[2] design patterns, elements of reusable object-oriented software, gof