Item 41: Understand implicit interfaces (implicit Interface) and compile-time polymorphism (polymorphism during compilation)
By Scott Meyers
Translator: fatalerror99 (itepub's nirvana)
Release: http://blog.csdn.net/fatalerror99/
The world of object-oriented programming (Object-Oriented Programming) is centered aroundExplicitInterfaces (explicit Interface) andRuntimePolymorphism (polymorphism during execution) is centered. For example, the following (meaningless) Class (class) is given ),
Class widget {
Public:
Widget ();
Virtual ~ Widget ();
Virtual STD: size_t size () const;
Virtual void normalize ();
Void swap (widget & other); // see item 25
...
};
And this (also meaningless) function ),
Void doprocessing (widget & W)
{
If (W. Size ()> 10 & W! = Somenastywidget ){
Widget temp (w );
Temp. normalize ();
Temp. Swap (w );
}
}
We can talk about w in doprocessing as follows:
- Because W is declared as a Type widget, W must support the widget interface (interface ). We can find this interface (Interface) in the source code (for example, the. h file of the widget) to see what it looks like, so we call itExplicit Interface(Explicit Interface) -- it is explicitly visible in the source code.
- Because some member functions (member functions) of widgets are virtual, W calls to these functions as follows:Runtime polymorphism(Execution duration polymorphism): the specific function to be called is determined based on the dynamic type (dynamic type) of w During execution (see item 37 ).
The world of templates and generic programming is fundamentally different. In that world, explicit interfaces and Runtime polymorphism continue to exist, but they are less important. Instead,Implicit Interfaces(Implicit Interface) andCompile-time Polymorphism(Polymorphism during compilation) moved to the foreground. To understand how this works, let's take a look at what happens when we change doprocessing from a function to a function template:
Template <typename T>
Void doprocessing (T& W)
{
If (W. Size ()> 10 & W! = Somenastywidget ){
TTemp (w );
Temp. normalize ();
Temp. Swap (w );
}
}
How can we talk about w in doprocessing?
- The interfaces required by W are determined by the operations performed on W in the template. In this example, the type (t) that appears as W must support size, normalize, and swap member functions (member function); copy construction (copy constructor) (used to create temp), and comparison of not equal to (used to compare with somenastywidget ). We will see that this is not very accurate in the future, but it is correct enough for now. What is important is that the expression that must be valid for template compilation must be supported by T.Implicit Interface(Implicit interface ).
- For example, operator> and operator! = Such calls to functions involving W may be accompanied by instantiating templates (instantiation templates) to make these calls successful. Such instantiation occurs during compilation. Because different template parameters (template parameters) are used to instantiate function templates (function templates), different functions are called.Compile-time Polymorphism(Polymorphism during compilation.
Even if you have never used a template, you should be familiar with the differences between runtime and compile-time polymorphism, it is similar to the dynamic binding (dynamic binding) that determines which of the following overload functions should be called (this occurs during compilation) and the virtual function (virtual function) Call) (This occurs at runtime. The difference between explicit and implicit interfaces is that new content related to the templates (Template) needs to be closely investigated.
An explicit interface is generally composed of function signatures, that is, function name, parameter type, return type, and so on. For example, the public interface (public interface) of the widget class (class ),
Class widget {
Public:
Widget ();
Virtual~ Widget ();
VirtualSTD: size_t size () const;
VirtualVoid normalize ();
Void swap (widget & other);
};
It consists of a constructor, A destructor, and a function size, normalize, and swap. In addition, parameter types (parameter type) and return types (return type) and the constnesses (constants) of these functions ). (It also includes copy constructor (copy constructor) and copy assignment operator (copy assignment operator) of compiler-generated (generated by the compiler)-See item 5 .) It may also contain typedefs, and if you dare to violate Item 22's suggestion of making data members (data member) Private (private), it includes data members (data member ), although in the current situation, it is not.
An implicit interface (implicit Interface) is very different. It is not based on function signatures (Function Recognition Feature. It is composed of validExpressions(Legal expression. Let's look at the conditions at the beginning of doprocessing template:
Template <typename T>
Void doprocessing (T & W)
{
If (W. Size ()> 10 & W! = Somenastywidget){
...
Implicit interface (implicit Interface) of T (W type) seems to have the following constraints:
- It must provide a member function (member function) that returns an integer named size ).
- It must support an operator used to compare two types of T objects! = Function. (Here, we assume that the type of somenastywidget is T .)
Because of the possibility of Operator Overloading (Operator overloading), these two constraints do not have to be met. Yes, T must support a size member function (member function), but it is worth mentioning that this function can be inherited from a base class (base class. However, this member function (member function) does not have to return an integer. It does not even have to return a value type. In this case, it does not even have to return a type that defines operator>! All it needs to do is to return an object (object) of a certain type of X. There is an object (object) of a type of x and an int (because 10 is of the int type) operator>. This operator> doesn't have to get a parameter of Type X, because as long as there is a objects (object) from Type X to the objects (object) of Type Y) implicit conversion (implicit transformation), it only gets a parameter of the Type Y is also possible!
Similarly, t supports Operator! = Is not necessary, because it is just like Operator! = It is acceptable to obtain an object of Type X and an object of Type Y. As long as t can be transformed into X, and somenastywidget type can be transformed into y, for operator! = Is valid.
(Note: The analysis here does not take into account the possibility of operator & being overloaded. This will explain the meaning of the above expression from logic and conversion to something about completely different .)
Most people have headaches when considering implicit interfaces (implicit Interface) for the first time, but they really don't need aspirin. Implicit interfaces (implicit Interface) is simply composed of a set of valid expressions. These expressions may seem complicated, but the constraints they apply are generally easy to understand. For example, this condition is given,
If (W. Size ()> 10 & W! = Somenastywidget )...
About functions size, operator>, operator & or operator! = Constraints on can hardly tell more things, but it is very easy to identify the constraints of the entire expression. The condition part of an if statement must be a Boolean expression (Boolean expression! = Which exact type is generated by somenastywidget? It must be compatible with bool. This is part of the implicit interface (implicit Interface) That Template (Template) doprocessing applies to its type parameter (type parameter) T. The rest of the interfaces required by doprocessing are copy constructor (copy constructor). The call of normalize and swap must be valid for objects (objects) of type T.
The Influence of implicit interface (implicit Interface) on parameters (parameters) of template (Template) is just like the objects (object) of explicit interfaces (explicit Interface) on a class (class) and both are checked during compilation. Just as you cannot use an object (object) (Code cannot be compiled) in a way that contradicts the explicit interface provided by its class (class, unless an object (object) supports the implicit interface (implicit Interface) required by the template, you cannot try to use this object (object) in a template) (The Code still cannot be compiled ).
Things to remember
- Both classes and templates support interfaces and polymorphism ).
- For classes (classes), interfaces (interfaces) are explicit and centered on function signatures (Function Recognition features. Polymorphism (polymorphism) occurs at runtime through virtual functions (virtual function.
- For template parameters (Template parameter), interfaces (Interface) is implicit (implicit) and is based on valid expressions (legal expression ). Polymorphism (polymorphism) occurs during compilation through template instantiation and function overloading resolution (function overload parsing.