Today, I asked about the C ++ polymorphism. As one of the three major object-oriented features, this is also very basic, and the result is quite tense, I only answered the need to use virtual functions to achieve polymorphism. Later, the interviewer said there were templates. I suddenly realized that after I came back, I looked at the polymorphism carefully. Now I will summarize it.
The so-called polymorphism literally refers to multiple States. Different operations are implemented using a unified interface. It is well known that running polymorphism is implemented using virtual functions, in addition, there are also static polymorphism, that is, the State relationship has been established at the time of compilation. In addition, there are also two sayings about polymorphism: function polymorphism and macro polymorphism. Next we will introduce them one by one.
I. Function Polymorphism
What should we do if we want to use functions to unify interfaces? Naturally, we think of function overloading with the same function name, but the list of function parameters is different regardless of the type or length, this method is used to achieve polymorphism, But I think function overloading and template polymorphism are actually the same, but we need to write multiple functions if it is an overloaded function, in the template, we use typedef. If we write a function, the matching will be replaced by the parameter type during the call. However, for different types of operations, the function implementation methods are different.
# Include <iostream> <br/> # include <string> <br/> using namespace STD; </P> <p> int add (INT num1, int num2) <br/>{< br/> return num1 + num2; <br/>}</P> <p> int add (INT num1, string str1) <br/>{< br/> return num1 + atoi (str1.c _ STR (); <br/>}</P> <p> void main () <br/> {<br/>/* function polymorphism */<br/> int num1 = 10; <br/> int num2 = 20; <br/> int result = add (num1, num2); <br/> cout <"function polymorphism add (INT num1, int num2) results in: "<result <Endl; <br/> string str1 =" 22 "; <br/> result = add (num1, str1 ); <br/> the result of cout <"function polymorphism add (INT num1, string str1) is:" <result <Endl; </P> <p>}
In this way, the compiler reintegrates functions based on different parameter lists, and the names of the two overloaded functions change.
2. Macro Polymorphism
Macro polymorphism means that the defined macro contains variables. In this way, the corresponding variables are also replaced when the macro is replaced, so that the macro can contain any parameter type.
# Include <iostream> <br/> # include <string> <br/> using namespace STD; </P> <p> # define add (A, B) A + B </P> <p> void main () <br/> {<br/>/* macro polymorphism */<br/> int num1 = 10; <br/> int num2 = 20; <br/> string str1 = "22"; <br/> string str2 = "33 "; <br/> cout <"macro polymorphism add (A + B) A + B:" <add (num1, num2) <Endl; <br/> cout <"macro polymorphism add (A + B) A + B:" <add (str1, str2) <Endl; <br/>}
Iii. Dynamic Polymorphism
In C ++, we mainly use inheritance mechanisms and virtual functions to call virtual functions by pointing to subclass objects through base class pointers or references, this will cause the virtual function of the corresponding object to be called. Because we use the base class pointer or reference in a unified manner, we cannot determine the virtual function to be called during compilation, perhaps the most convenient part of a virtual function is to process a collection, when each object is different, the following code
# Include <iostream> <br/> # include <string> <br/> # include <vector> <br/> using namespace STD; <br/>/* virtual function mechanism */<br/> class base <br/> {<br/> Public: <br/> virtual void print () = 0; <br/>}; </P> <p> class Child1: public base <br/>{< br/> void print () <br/>{< br/> cout <"I Am a Child1 class" <Endl; <br/>}< br/>}; <br/> class child2: public base <br/> {<br/> void print () <br/> {<br/> cout <"I Am a child2 class" <Endl; <br/>}< br/>}; <br/>/* If the objects of functions in the container are of different classes, at this time, it is very convenient to use polymorphism */<br/> void function (const vector <base *> & V) <br/> {<br/> for (INT I = 0; I <v. size (); ++ I) <br/>{< br/> v. at (I)-> Print (); <br/>}</P> <p> void main () <br/> {<br/>/* virtual function polymorphism */<br/> Child1 Child1; <br/> child2 child2; <br/> base * P; <br/> P = & Child1; <br/> P-> Print (); <br/> P = & child2; <br/> P-> Print (); <br/> vector <base *> basevector; <br/> basevector. push_back (& Child1); <br/> basevector. push_back (& child2); <br/> function (basevector); <br/>}
Iv. Static Polymorphism
If the template is used to implement the above example, we do not need to let these two classes inherit the same parent class. during compilation, two different functions are generated, static polymorphism will lead to larger programs, but this will be more efficient than running polymorphism, but we can't process heterogeneous objects using function templates, it means that if the container is operated in the function template, but the objects in the container are different, because we cannot put two different types of objects in the same container, therefore, the more common method is to combine Dynamic and Static polymorphism.
# Include <iostream> <br/> # include <string> <br/> # include <vector> <br/> using namespace STD; <br/>/* virtual function mechanism */<br/> class base <br/> {<br/> Public: <br/> virtual void print () = 0; <br/>}; </P> <p> class Child1: public base <br/>{< br/> void print () <br/>{< br/> cout <"I Am a Child1 class" <Endl; <br/>}< br/>}; <br/> class child2: public base <br/> {<br/> void print () <br/> {<br/> cout <"I Am a child2 class" <Endl; <br/>}< br/>}; <br/>/* If the objects of functions in the container are of different classes, at this time, it is very convenient to use polymorphism */<br/> void function (const vector <base *> & V) <br/> {<br/> for (INT I = 0; I <v. size (); ++ I) <br/>{< br/> v. at (I)-> Print (); <br/>}</P> <p>/* Static polymorphism, use template */<br/> template <typename T> <br/> void tempaltefuncion (const vector <t *> & V) <br/> {<br/> for (INT I = 0; I <v. size (); ++ I) <br/>{< br/> v. at (I)-> Print (); <br/>}< br/> void main () <br/> {<br/>/* mix of virtual function polymorphism templates */<br/> Child1 Child1; <br/> child2 child2; <br/> base * P; <br/> P = & Child1; <br/> P-> Print (); <br/> P = & child2; <br/> P-> Print (); <br/> vector <base *> basevector; <br/> basevector. push_back (& Child1); <br/> basevector. push_back (& child2); <br/> function (basevector); <br/> tempaltefuncion (basevector); <br/>}
Summary)
Dynamic polymorphism only requires one polymorphism function. The size of the executable code generated is small. Static polymorphism must generate different template entities for different types, and the size will be larger, but the generated code is faster, because no indirect operation is required through the pointer. Static polymorphism is more type-safe than dynamic polymorphism because all bindings are checked during compilation. As shown in the previous example, you cannot insert an incorrect type object into a container instantiated from a template. In addition, as you have seen, dynamic polymorphism can elegantly process heterogeneous object sets, while static polymorphism can be used to implement secure and efficient homogeneous object set operations.
Static polymorphism brings the concept of generic programming to C ++. Generic programming can be considered as a template programming of "component functions are designed based on the overall framework. STL is a model of generic programming. STL is a framework that provides a large number of algorithms, containers, and iterators, all implemented using template technology. Theoretically, STL functions can be implemented using dynamic polymorphism, but the performance will be compromised.
Static polymorphism also brings the concept of generic patterns to the C ++ community. In theory, every design pattern that needs to be supported through virtual functions and class inheritance can use the template-Based Static polymorphism technology (or even the combination of dynamic and static polymorphism technologies) and implementation. As you can see, Andrei Alexandrescu's genius works modern c ++ design: Generic programming and design patterns applied (Addison-Wesley) and Loki libraries are already ahead of us.