When we were talking about C + +, we often asked: "Can virtual functions be declared inline?" Now, we can hardly hear the question. Now you hear: "You should not make print inline." Declaring a virtual function inline is wrong! "
The two main reasons for this claim are (1) the virtual function is in the run-time resolution and inline is a compile-time action, so, we declare a virtual function inline and have no effect; (2) declaring a virtual function inline results in a multiple-copy of the function, And we're spending storage space for a function that shouldn't be inline at any time. It's not a brain thing to do.
But that is not the case. Let's take a look at the first one: In many cases, virtual functions are statically resolved-for example, when you call a virtual function of a base class in a derived class virtual function. Why do you do that? Encapsulation. A more obvious example is the derived class destructor call chain. All virtual destructors are statically resolved, except that they initially trigger the virtual destructor of the destructor chain. If you do not inline the virtual destructor of the base class, we cannot profit from it [a]. Is this different from a virtual destructor that doesn't inline? If the inheritance system is deeper and there are many instances of such classes to be destroyed, the answer is yes.
Let's look at another example of not using destructors, imagine designing a library class. We will materiallocation as a member of the abstract class librarymaterial. Declare its print member function as a pure virtual function, and provide a function definition: it outputs materiallocation.
Class Librarymaterial {
Private
Materiallocation _loc; Shared data
...
Public
Declares pure virtual function
inline virtual void print (ostream& = cout) = 0;
};
We actually want to encapsulate the handling of the
Location of the material within a base class
Librarymaterial print () method-we just don ' t want it
Invoked through the virtual interface. That's, it is
Invoked within a derived class print () method
inline void
Librarymaterial::
Print (Ostream &os) {OS _loc;}
Next, we introduce a book class whose print function prints the title, author, and so on. Before that, it calls the print function of the base class (librarymaterial::p rint ()) to display the book position (materiallocation). As follows:
inline void
Book::
Print (Ostream &os)
{
OK, this is resolved statically,
And therefore is inline expanded ...
Librarymaterial::p rint ();
OS "title:" "_title
"Author" "_author" ENDL;
}
The audiobook class, derived from the book class, and adds additional information, such as a side-by, audio format, and so on. These things are printed with its print function. Before that, we need to call book::p rint () to display the preceding information.
inline void
Audiobook::
Print (Ostream &os)
{
OK, this is resolved statically,
And therefore is inline expanded ...
Book::p rint ();
Os "" Narrator: "_narrator" ENDL;
}
This is the same as the example of the virtual destructor call chain, except that the virtual function that was originally invoked was not statically resolved, and the rest was expanded in situ. This unnamed hierarchical design pattern is significantly less effective if we never declare a virtual function to be Inli Ne.
So for the second reason, the question of code bloat? Let's analyze it if we write:
Librarymaterial *p =
New Audiobook ("Mason & Dixon",
"Thomas Pynchon", "Johnny Depp");
...
P->print ();
Is this print instance inline? No, of course not. This has to be done through the virtual mechanism in the runtime resolution. Does this let the print instance discard the inline declaration on it? This call is converted to the following form (pseudo code):
Pseudo C + + Code
Possible Transformation of P->print ()
(*p->_vptr[2]) (p);
Where 2 represents the location of print within the associated virtual function table. Because calling print is done through function pointer _vptr[2], the compiler cannot The call address is statically determined, and this function is not inline.
Of course, the inline entity (definition) of the virtual function print must also appear somewhere. That is, there is at least one function entity that is unfolding at the address of the virtual table call. How does the compiler decide when to expand this function entity? One of the compilation (implementaion) policies is to generate this function entity while virtual table is generated. This means that a function entity is generated for virtual table for each derived class.
How many vitrual table will be generated in an applicable class [b]? Oh, this is a good question. In the C + + standard, the virtual function behavior is stipulated, but the function implementation is not stipulated. Since virtual table is not regulated in the C + + standard, it is clear that how the virtual table is generated and how many vitrual table to generate is not specified. How many? Of course, we just need one. Stroustrup's Cfront compiler handles these situations cleverly. (Stan and Andy Koenig described the algorithm in the March 1990 C + +, "article Virtual Tables in C + + optimizing Ease 2.0. ")
Moreover, the C + + Standard now requires this inline functions behave as though only one definition for a inline function exists in the "program even though" function may is defined in different files. The new rule requires the compiler to expand only one inline virtual function. If a single point is widely used, the problem of code bloat caused by the inline of a virtual function disappears.
[standard:9.3.8: C + +, member function of the local class shall is defined inline in their class defination, if they are def Ined at all]
============================
Nasa
[A] function call overhead, which takes at least two indirect processes when calling a base-class virtual function (S. B.lippman: "Inside the C + + Object Model")
[B] A product class (?)
Summarize:
is a virtual function inline in the call chain and other places useful ~
If you do not join the inline declaration, as a good compiler, you will optimize (virtual destructor)
In a long function call chain, it is best to inline the function of the base class in the chain, thus saving overhead
As to where to inline, the compiler decides, because the C + + standard does not stipulate
The new C + + standard (which may not pass) stipulates that inline is only valid for the product class and only one action at a time
Ensure code does not inflate excessively
The inline action is created together with vtable at the same time that the product class is instantiated.