Article 4: static and polymorphism.
In this article, we will discuss the relationship between static and Polymorphism in C ++. We all know that C ++ is not a "dynamic" language. Although it provides polymorphism that is equally powerful than other dynamic languages, many times we choose C ++, the high performance brought about by zhongzheng's "static" is important. StaticProgramThe running process is static and fixed (especially the memory address). Of course, "polymorphism" is the opposite concept. This article does not discuss the functions of static (member) variables or static (member) functions. Instead, it discusses "static" behavior and compares "polymorphism ". The static content here refers to compiler time, that is, binding at compilation, early binding, and static Association; "polymorphism" means real runtime binding, late binding, and dynamic Association.
It is amazing that this concept of opposition can coexist and work together in C ++.
The old rule is a short one.CodeAsk the question: what happens when a virtual member function (polymorphism) is declared as a static member function in its subclass (or vice versa?
1. When a virtual function encounters a static function
1 # Include <iostream> 2 Using Namespace STD; 3 4 Class Base 5 { 6 Public : 7 Virtual Void Foo (Void ) {Cout < " Base: Foo () " < Endl ;} 8 }; 9 10 Class Derived: Public Base 11 { 12 Public : 13 Void Foo ( Void ) {Cout < " Derived: Foo () " < Endl ;} 14 }; 15 16 Class Derivedagain: Public Derived 17 { 18 Public : 19 Static Void Foo ( Void ) {Cout < " Derivedagain: Foo () " < Endl ;} 20 }; 21 22 Int Main (Int Argc, Char ** Argv) 23 { 24 Derivedagain da; 25 Base * pb = & Da; 26 27 28 Da. Foo (); 29 Pb-> Foo (); 30 Return 0 ; 31 }
What is the result of the above Code? Are you sure the above Code can be compiled? On the author's Ubuntu 12.04 + GCC 4.6.3 machine, the above CodeCompilation fails. The following information is displayed:
1 stawithvir. CPP : 19 : 17 : Error: 'static void derivedagain: Foo () 'cannot be declared 2 stawithvir. CPP : 13 : 10 : Error: Since 'virtual void derived: Foo () 'declared in base class
Obviously,The reason for compilation failure is that the virtual function is declared as static in the derivedagain class.The compiler rejects the peaceful coexistence of "static" and "polymorphism. The reason for this is very simple. The static member function is shared at the class level, does not belong to any object, does not pass in this pointer, and cannot access non-static members. However, the requirement of the virtual function is the opposite, you need to bind the object (this pointer) to obtain the virtual table and then call it. How can the compiler handle such conflicting behaviors, because it chooses to report errors to express dissatisfaction. We can now remember the conclusion:Virtual functions cannot be declared as static.
Next, you may ask, isn't it clear that the compilation fails? Why do we need to discuss it? This is because the code can be compiled and output in Some compilers (such as vc6 and vc2008), which is incredible? However, these compilers also give a warning (involved in msdn warning c4526) that static functions cannot be called using virtual functions. Although compiled, the idea is consistent with the above GCC.
1 //Output result2 Derivedagain: Foo ()3Derived: Foo ()
Da. foo () Output derivedagain: Foo () No doubt (no dynamic binding is generated no matter whether the method is virtual or not by calling the object ); pb-> Foo () Output derived: Foo () needs to be explained, because Pb is a pointer to call the virtual method, resulting in "polymorphism ", during dynamic binding, we found that Pb points to the derivedagain object type, so we went to the address of Foo () in the derivedagain object virtual table. However, we found that the Foo () in the derivedagain virtual table () is actually derived: Foo (),Because Foo in derivedagain has been declared as static, the address of this function in the virtual table is not updated.(In fact, because derivedagain does not declare any new virtual functions, the virtual table of its object is exactly the same as that of the derived object. If you are interested, you can view it through Assembly ), therefore, the output is derived: Foo (), which proves from one side that the latest virtual function version is used in the inheritance chain.
At this point, the problem has been clearly explained. Remember the conclusion again:Static member functions cannot be virtual functions at the same time..
2. overload is not a true polymorphism, and its essence is static behavior.
I have seen more than once that many books and materials often classify "overload" into polymorphism when talking about C ++ polymorphism. There seems to be nothing wrong with this statement. In fact, I think it is very inappropriate. Although the feature is overloaded, the feature is differentiated (note that parameters are different for the same function name, or functions with the same name but whether they are const member functions ), the method calling with the same function name produces different behaviors, which indeed reflects the concept of "polymorphism",The essence of heavy load is static binding, which determines which method to call during compilation, rather than dynamic binding, so it is not a real polymorphism.. Therefore, be clear-headed, that is, if the relationship between two (or more) methods is "overload", then there will be no real polymorphism.
3. When will true polymorphism be produced?
After discussing the overload, we should talk about when to generate a real multi-state behavior, that is, dynamic binding? The author summarizes three necessary conditions as follows:
(1) The method is virtual;
(2) override generation;
(3) Call the corresponding virtual method through a pointer or reference, rather than through an object call. Through an object call method, whether the method is a virtual method or not, it is a static Association.
Condition (1) (2) It is obvious that if the method is virtual and does not cover it, why is the "State" of "multiple "? However, condition (3) is easily ignored by new users becauseBy calling an object, the object type is known, so static binding does not produce polymorphism. When a virtual method is called through a pointer or reference, the pointer or reference to a specific type cannot be determined during the compilation period. Therefore, the method can only be dynamically programmed to generate polymorphism..
4. Incorrect code will prevent Polymorphism
Now let's take a look at a short piece of code from C ++ primer plus:
1 Class Base 2 { 3 Public : 4 Virtual Void Foo ( Void ){...} 5 ... 6 }; 7 8 Class Derived: Public Base 9 { 10 Public : 11 Void Foo ( Void ){...} 12 ... 13 }; 14 15 // Version 1 16 Void Show1 ( Const Base & B) 17 { 18 B. Foo (); 19 } 20 21 // Version 2 22 Void Show2 (Base B) 23 { 24 B. Foo (); 25 } 26 27 Int Main (Int Argc, Char ** Argv) 28 { 29 Derived D; 30 Show1 (d ); 31 Show2 (d ); 32 Return 0 ; 33 }
What is the problem with the above Code? We can see that the only difference between the show functions of the two versions is that version 1 transfers objects by reference, and Version 2 transfers objects by value. In the main function, a new derived object is created and passed to the function of version 1. Because the parameter B in version 1 is of the reference type, OK, no problem, B. foo () will be called Based on the object actually pointed to by B, that is, derived: Foo () can be called correctly, while version 2 parameter B is of the object type (B is base (const base &) copy a base object created by the constructor, and automatically convert the forced type so that the base class copy constructor can reference a subclass object). According to the above 3rd points, B. foo () will be called to base: Foo () based on the object type (base), without producing polymorphism. That is,Because of passing by value, dynamic binding is blocked and multi-state behavior is blocked..
Speaking of this, it is also a common problem, that isUnless this is required, do not pass parameters by value, instead select a pointer or reference, We will discuss this issue later in this series.