Mock the virtual function?
In recent days, I read "ATL INTERNALS" and saw a small trick about Template in the appendix - Simulation Dynamic Binding:
Template
Class array {
PUBLIC:
......
Virtual Int Compare (Const Array
& rhs) = 0;
Bool Operator <(Const Array)
& rhs)
{Return this-> Compare (rhs) <0;}
Bool Operator> (Const Array)
& rhs)
{RETURN THIS-> Compare (rhs)> 0;
BOOL Operator == (Const Array
& rhs)
{RETURN THIS-> Compare (rhs) == 0;}
T M_RG [1024];
}
Then derive class override this virtual function to get polymorphism:
Class String: Public Array
{
PUBLIC:
INT COMPARE (Const Array)
& rhs)
{RETURN STRCMP (M_RG, RHS.M_RG);}
}
In order to realize the virtual function requires a VPTR and a VTABLE, and the correct function can be called at least twice.
Then introduce a way of providing efficiency:
Template
Class array {
PUBLIC:
......
Bool Operator <(Const Array)
& rhs)
{return static_cast
(this) -> COMPARE (RHS) <0;}
Bool Operator> (Const Array)
& rhs)
{return static_cast
(this) -> COMPARE (RHS)> 0;}
BOOL Operator == (Const Array
& rhs)
{return static_cast
(this) -> COMPARE (RHS) == 0;} T m_RG [1024];
Note that Array Template accepts an additional parameter - the name of the derived class. It uses this class name to complete the stacked mandatory conversion. Because the compiler will expand the code of the base class while instantiation (avatar), the static mandatory conversion completes a fully secure downward conversion.
Class String: Public Array
PUBLIC:
INT COMPARE (Const Array)
& rhs)
{RETURN STRCMP (M_RG, RHS.M_RG);}
}
This technology makes us see and feel dynamic binding without using virtual members. Is it really amazing? The virtual function really can be used to simulate through the template? of course not
I still felt confused when I started, but I felt that this thing just seems to be like virtual functions, but there are a lot of limitations. So I went online to ask the master. GIGIX was exposed to me at first, and I blamed me bad. Ask Babysloth, one list of code he knows this. He said: "This is called Curiously Recurring Template Pattern, which is recorded first by Bell-Lab"
Then, I accidentally saw the article I used to download ATL related technologies, I said something in detail. The article is "ATL Under The Hood PART 3" on CodeGuru. A short program illustrates this thing: #include
Using namespace std;
Class base {
PUBLIC:
Virtual void fun () {
Cout << "Base :: fun" << endl;
}
Void dosomething () {
Fun ();
}
}
Class Drive: Public base {
PUBLIC:
Void fun () {
Cout << "drive :: fun" << Endl;
}
}
Int main () {
DRIVE OBJ;
Obj.dosomething ();
Return 0;
}
The behavior in this program is the same as the following programs:
#include
Using namespace std;
Template
Class base {
PUBLIC:
Void fun () {
Cout << "Base :: fun" << endl;
}
Void dosomething () {
T * pt = static_cast
(this);
Pt-> fun ();
}
}
Class Drive: Public Base
{
PUBLIC:
Void fun () {
Cout << "drive :: fun" << Endl;
}
}
Int main () {
DRIVE OBJ;
Obj.dosomething ();
Return 0;
}
The result of this is the same. Quote a sentence of insects: "Different efficiency".
The problem is that here is only a part of the virtual function, and the virtual function is a classic example is an array to save the fault pointer, and the modified virtual function is modified by the pointer. Can you use this simulated version? No!
Don't do this below:
#include
Using namespace std;
Template
Class base {
PUBLIC:
Void fun () {
Cout << "Base :: fun" << endl;
}
Void dosomething () {
T * pt = static_cast
(this);
Pt-> fun ();
}
}
Class Drive1: Public Base
{
PUBLIC:
Void fun () {
Cout << "drive1 :: fun" << Endl;
}
}
Class Drive2: Public Base
{
PUBLIC:
Void fun () {
Cout << "drive2 :: fun" << Endl;
}
}
Int main () {
Base
* PBASE = NULL; PBASE = New Drive1; PBase-> DOSMETHING (); delete PBase; PBase = New Drive2; PBase-> DOSMETHING (); return 0;}
Because Drive2 does not match DRIVE1. In addition, such analog virtual functions can only maintain one layer, and cannot be anywhere in the derived level like a real virtual function, the virtual function has always been virtual function. E.g:
#include
Using Namespace Std; Template
Class base {
PUBLIC:
Void fun () {
Cout << "Base :: fun" << endl;
}
Void dosomething () {
T * pt = static_cast
(this);
Pt-> fun ();
}
}
Class Drive: Public Base
{
PUBLIC:
Void fun () {
Cout << "drive :: fun" << Endl;
}
}
Class MostDrive: Public Drive {
PUBLIC:
Void fun () {
Cout << "MostDrive :: fun" << Endl;
}
}
Int main () {
MostDrive obj;
Obj.dosomething ();
Return 0;
}
Output is drive :: fun instead of MostDrive :: fun
in conclusion
The conclusion is that there is nothing to simulate the virtual function, just in this scenario very much like virtual functions, several important natures of the virtual function is not supported. This is just an IDIOM in a program design, one of many techniques for templates.
Main use: When the parent class needs sub-information. A function B in the subclass is required in a function A in the parent class to achieve some of the subclasses to customize certain behaviors.
Main principle: Different interpretations of PT-> Fun () through the forced type conversion of this. This explanation is during compilation. During the compilation, the type parameters of the template are expanded. The type of conversion to this is determined according to the parameter, and the explanation of PT-> Fun () is also determined. So simulate static polymorphism.
How to use: The method used is not the same as the virtual function to invoke the virtual function through the object's pointer. Instead, by calling a normal function inherited from the base class, the function of calling "rewritable" derived class is called in this function.
The main defect: is that the virtual property does not have the transfer property, and does not have a dynamic polymorphism. The so-called polymorphism is just the meaning of the specific function call by means of implied by the template parameters you passed.
I feel: According to Babysloth, this is also a design pattern. Plus the "STL source profiling" feeling mode, ITERATOR, ITERATOR, ITATOR, I think the design model is very profound. After the introduction of mathematical analysis, you must have a few books in this regard after mathematical analysis.