The run-time cost of each feature is obtained from the above figure as follows:
Characteristics |
Time Overhead |
Space overhead |
RTTI |
Several cosmetic comparisons and one access operation (possibly 1 or 2 cosmetic additions) |
One Type_info object per type (including type ID and class name), typically less than 32 bytes |
virtual function |
One plastic addition and one pointer indirect reference |
A virtual table of each type, typically less than 128 bytes A virtual table pointer, typically less than 8 bytes, for each object (in most cases) |
Virtual base class |
When you access a data member of a virtual base class or its virtual function from a subclass of a virtual inheritance, you add two pointer indirect references and one cosmetic addition (in some cases, you can optimize for a pointer indirect reference). |
A virtual base class table of each type, typically less than 32 bytes Several virtual base class table pointers per object, typically less than 8 bytes When virtual functions are used at the same time, virtual base class tables can be merged into virtual tables (virtual table) , and each object's virtual base class table pointer (VBPTR) can also be omitted (just vptr). In fact, many implementations do this. The disadvantage of this is that you need to prepare multiple virtual tables for some intermediate types, such as B1, B2, and so on. This is true if the specified type has only one virtual base class in its class hierarchy, most of which use a virtual base class. For example, if there is only one virtual base class in the above case, you can replace vbptr directly with the offset address of the virtual base class, which will save you a pointer indirect reference, thereby increasing your efficiency. Many compilers automatically turn on such optimizations. In addition, this value is known at compile time because in many situations where you would otherwise need to access the offset field in a virtual table (for example, when you invoke certain virtual functions). The conversion from the base class object to the derived class this pointer can be completed by just one integer immediate number addition. Therefore, in the absence of any effect on time efficiency, you can retain only one vbptr pointer (meaning: The vbptr in the B2 in the above example can be omitted). This optimization method is often used with the previous mentioned, in the case of Tankuiki class to replace the vbptr directly with the virtual base class of the approach to use together to achieve a better balance between time efficiency and space efficiency, for example: VC often use such optimization method. |
* where "each type" or "per object" refers to the type/object to which the attribute is used. This overhead is not increased for types and their objects that are not used for these features |
It can be seen that the good legends about God's "drop pies when you're hungry and sleep off your wife" are pure rumors. Any artifact will not be perfect, there is always the choice of design, there is its adaptation of the occasion also has its not applicable places. Each feature in C + + is gradually refined from the normal production life of the programmer. Using them in an incorrect situation is bound to cause logical, behavioral, and performance problems. For the above characteristics, it should only be used only if necessary and reasonable. "dynamic_cast" is used to roam through the class hierarchy and to freely upward, downward, or cross coercion of pointers or references. "typeid" is used to get the exact type of an object or reference, unlike "dynamic_cast", it is usually an error to have "typeID" acting on the pointer, and to get the type_info of a pointer to an object, you should first dereference it (for example: "typeID (*p);" )。 Generally speaking, the problem that can solve with virtual function do not use "dynamic_cast", can use "dynamic_cast" to solve is not to use "typeID". Like what:
void Rotate (in const cshape& is) { if (typeid (IS) = = typeID (ccircle)) { // ... } else if (typeid (IS) = = typeID (ctriangle)) { // ... } else if (typeid (IS) = = typeID (csqucre)) { // ... }
// ... } |
The above code with "dynamic_cast" write will be slightly better, of course, the best way is to define a virtual function named "Rotate" in Cshape. Virtual functions are the least expensive and most commonly used mechanism in C + + Run-time polymorphic features. The benefits and effects of virtual functions here, you should pay attention to situations where performance is demanding, or frequent calls, to places where performance is more significant (such as thousands of calls per second, and very simple event handlers for their own content), use virtual functions with caution. One particular point to note is that the invocation cost of a virtual function is equivalent to an indirect function call through a function pointer (for example, common in classic C programs, by pointing to a function pointer member in a struct, and by invoking a function in dll/so). A pointer indirect reference is trivial compared to the cost of the function call itself (saving the field-> pass parameter-> passing the return value-> recovery site). This makes it possible to afford the slightest extra overhead of virtual methods in most situations where functions can be used . As a kind of object-oriented language supporting multiple inheritance, virtual base class is a necessary means to ensure the correct consistency of class hierarchy. However, you should try to avoid using the services provided by the base class frequently and where performance requirements are high. Virtual base classes can also be lifted when there are no data members in the base class. For example, in the above illustration, if the data member does not exist in the class "BB", then "BB" can be inherited as a normal base class by "B1" and "B2" respectively. This optimization relieves the overhead caused by the virtual base class on the premise of achieving the same effect. However, this optimization will also bring some problems: from "DD" Up to "BB" will cause ambiguity, the failure of the class hierarchy of the logical relationship. The spatial overhead of the above features is generally acceptable, and there are some exceptions, such as the case where the storage layout needs to be compatible with the traditional C structure, where the alignment is considered, and when many objects need to be instantiated at the same time for a class that is small in size. |