⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mi24.htm

📁 高效c++编程
💻 HTM
📖 第 1 页 / 共 3 页
字号:
</NOBR></P><A NAME="42825"></A>
<P><A NAME="dingp30"></A>
For example, consider this, which I generally call "the dreaded multiple inheritance <NOBR>diamond:"<SCRIPT>create_link(30);</SCRIPT>
</NOBR></P>

<SPAN ID="Image5of1" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_119A1.GIF" BORDER=0></SPAN>
<SPAN ID="Image5of2" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_119A2.GIF" BORDER=0></SPAN>
<SPAN ID="Image5of3" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_119A3.GIF" BORDER=0></SPAN>
<SPAN ID="Image5of4" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_119A4.GIF" BORDER=0></SPAN>
<SPAN ID="Image5of5" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_119A5.GIF" BORDER=0></SPAN>

<SPAN ID="Image5of6" STYLE="position: relative; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_119A5.GIF" BORDER=0></SPAN>

<A NAME="42846"></A>
<P><A NAME="dingp31"></A>
Here <CODE>A</CODE> is a virtual base class because <CODE>B</CODE> and <CODE>C</CODE> virtually inherit from it. With some compilers (especially older compilers), the layout for an object of type <CODE>D</CODE> is likely to look like <NOBR>this:<SCRIPT>create_link(31);</SCRIPT>
</NOBR></P>

<SPAN ID="Image6of1" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_119B1.GIF" BORDER=0></SPAN>
<SPAN ID="Image6of2" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_119B2.GIF" BORDER=0></SPAN>
<SPAN ID="Image6of3" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_119B3.GIF" BORDER=0></SPAN>
<SPAN ID="Image6of4" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_119B4.GIF" BORDER=0></SPAN>
<SPAN ID="Image6of5" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_119B5.GIF" BORDER=0></SPAN>

<SPAN ID="Image6of6" STYLE="position: relative; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_119B5.GIF" BORDER=0></SPAN>

<A NAME="42926"></A>
<P><A NAME="dingp32"></A>
It seems a little strange to place the base class data members at the end of the object, but that's often how it's done. Of course, implementations are free to organize memory any way they like, so you should never rely on this picture for anything more than a conceptual overview of how virtual base classes may lead to the addition of hidden pointers to your objects. Some implementations add fewer pointers, and some find ways to add none at all. (Such implementations make the vptr and vtbl serve double <NOBR>duty).<SCRIPT>create_link(32);</SCRIPT>
</NOBR></P><A NAME="42934"></A>
<P><A NAME="dingp33"></A>
If we combine this picture with the earlier one showing how virtual table pointers are added to objects, we realize that if the base class <CODE>A</CODE> <A NAME="p120"></A>in the hierarchy on <a href="#p119">page 119</A> has any virtual functions, the memory layout for an object of type <CODE>D</CODE> could look like this:<SCRIPT>create_link(33);</SCRIPT>
</P>
<SPAN ID="Image7of1" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_120A1.GIF" BORDER=0></SPAN>
<SPAN ID="Image7of2" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_120A2.GIF" BORDER=0></SPAN>
<SPAN ID="Image7of3" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_120A3.GIF" BORDER=0></SPAN>
<SPAN ID="Image7of4" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_120A4.GIF" BORDER=0></SPAN>
<SPAN ID="Image7of5" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_120A5.GIF" BORDER=0></SPAN>

<SPAN ID="Image7of6" STYLE="position: relative; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_120A5.GIF" BORDER=0></SPAN>

<A NAME="84197"></A>
<P><A NAME="dingp34"></A>
Here I've shaded the parts of the object that are added by compilers. The picture may be misleading, because the ratio of shaded to unshaded areas is determined by the amount of data in your classes. For small classes, the relative overhead is large. For classes with more data, the relative overhead is less significant, though it is typically <NOBR>noticeable.<SCRIPT>create_link(34);</SCRIPT>
</NOBR></P><A NAME="51435"></A>
<P><A NAME="dingp35"></A>
An oddity in the above diagram is that there are only three vptrs even though four classes are involved. Implementations are free to generate four vptrs if they like, but three suffice (it turns out that <CODE>B</CODE> and <CODE>D</CODE> can share a vptr), and most implementations take advantage of this opportunity to reduce the compiler-generated <NOBR>overhead.<SCRIPT>create_link(35);</SCRIPT>
</NOBR></P><A NAME="42998"></A>
<P><A NAME="dingp36"></A>
We've now seen how virtual functions make objects larger and preclude inlining, and we've examined how multiple inheritance and virtual base classes can also increase the size of objects. Let us therefore turn to our final topic, the cost of runtime type identification <NOBR>(RTTI).<SCRIPT>create_link(36);</SCRIPT>
</NOBR></P><A NAME="43023"></A>
<P><A NAME="dingp37"></A>
RTTI lets us discover information about objects and classes at runtime, so there has to be a place to store the information we're allowed to query. That information is stored in an object of type <CODE>type_info</CODE>, and you can access the <CODE>type_info</CODE> object for a class by using the <CODE>typeid</CODE> <NOBR>operator.<SCRIPT>create_link(37);</SCRIPT>
</NOBR></P><A NAME="80055"></A>
<P><A NAME="dingp38"></A>
There only needs to be a single copy of the RTTI information for each class, but there must be a way to get to that information for any object. Actually, that's not quite true. The language specification states that we're guaranteed accurate information on an object's dynamic type <A NAME="p121"></A>only if that type has at least one virtual function. This makes RTTI data sound a lot like a virtual function table. We need only one copy of the information per class, and we need a way to get to the appropriate information from any object containing a virtual function. This parallel between RTTI and virtual function tables is no accident: RTTI was designed to be implementable in terms of a class's <NOBR>vtbl.<SCRIPT>create_link(38);</SCRIPT>
</NOBR></P><A NAME="43038"></A>
<P><A NAME="dingp39"></A>
For example, index 0 of a vtbl array might contain a pointer to the <CODE>type_info</CODE> object for the class corresponding to that vtbl. The vtbl for class <CODE>C1</CODE> on <a href="#p114">page 114</A> would then look like <NOBR>this:<SCRIPT>create_link(39);</SCRIPT>
</NOBR></P>

<SPAN ID="Image8of1" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_121A1.GIF" BORDER=0></SPAN>
<SPAN ID="Image8of2" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_121A2.GIF" BORDER=0></SPAN>
<SPAN ID="Image8of3" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_121A3.GIF" BORDER=0></SPAN>
<SPAN ID="Image8of4" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_121A4.GIF" BORDER=0></SPAN>
<SPAN ID="Image8of5" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_121A5.GIF" BORDER=0></SPAN>

<SPAN ID="Image8of6" STYLE="position: relative; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_121A5.GIF" BORDER=0></SPAN>

<A NAME="43034"></A>
<P><A NAME="dingp40"></A>
With this implementation, the space cost of RTTI is an additional entry in each class vtbl plus the cost of the storage for the <CODE>type_info</CODE> object for each class. Just as the memory for virtual tables is unlikely to be noticeable for most applications, however, you're unlikely to run into problems due to the size of <CODE>type_info</CODE> <NOBR>objects.<SCRIPT>create_link(40);</SCRIPT>
</NOBR></P><A NAME="43113"></A>
<P><A NAME="dingp41"></A>
The following table summarizes the primary costs of virtual functions, multiple inheritance, virtual base classes, and <NOBR>RTTI:<SCRIPT>create_link(41);</SCRIPT>
</NOBR></P><A NAME="42824"></A>

<TABLE WIDTH="90%"><TR>
<TH ALIGN="LEFT" VALIGN="BOTTOM">Feature</TH>
<TH ALIGN="CENTER">Increases<BR>Size of Objects</TH>
<TH ALIGN="CENTER">Increases<BR>Per-Class Data</TH>
<TH ALIGN="CENTER">Reduces<BR>Inlining</TH></TR>
<TR><TD><A NAME="43238"></A>
Virtual Functions</TD><TD ALIGN="CENTER">Yes</TD><TD ALIGN="CENTER">Yes</TD><TD ALIGN="CENTER">Yes</TD></TR>
<TR><TD><A NAME="43248"></A>
Multiple Inheritance</TD><TD ALIGN="CENTER">Yes</TD><TD ALIGN="CENTER">Yes</TD><TD ALIGN="CENTER">No</TD></TR>
<TR><TD><A NAME="43227"></A>
Virtual Base Classes</TD><TD ALIGN="CENTER">Often</TD><TD ALIGN="CENTER">Sometimes</TD><TD ALIGN="CENTER">No</TD></TR>
<TR><TD><A NAME="43229"></A>
RTTI</TD><TD ALIGN="CENTER">No</TD><TD ALIGN="CENTER">Yes</TD><TD ALIGN="CENTER">No</TD></TR>
</TABLE>

<A NAME="41312"></A>
<P><A NAME="dingp42"></A>
Some people look at this table and are aghast. "I'm sticking with C!", they declare. Fair enough. But remember that each of these features offers functionality you'd otherwise have to code by hand. In most cases, your manual approximation would probably be less efficient and less robust than the compiler-generated code. Using nested <CODE>switch</CODE> statements or cascading <CODE>if</CODE>-<CODE>then</CODE>-<CODE>else</CODE>s to emulate virtual function calls, for example, yields more code than virtual function calls do, and the code runs more slowly, too. Furthermore, you must manually track object types yourself, which means your objects carry around type tags of their own; you thus often fail to gain even the benefit of smaller <NOBR>objects.<SCRIPT>create_link(42);</SCRIPT>
</NOBR></P><A NAME="43297"></A>
<A NAME="p122"></A>
<P><A NAME="dingp43"></A>
It is important to understand the costs of virtual functions, multiple inheritance, virtual base classes, and RTTI, but it is equally important to understand that if you need the functionality these features offer, you <I>will</I> pay for it, one way or another. Sometimes you have legitimate reasons for bypassing the compiler-generated services. For example, hidden vptrs and pointers to virtual base classes can make it difficult to store C++ objects in databases or to move them across process boundaries, so you may wish to emulate these features in a way that makes it easier to accomplish these other tasks. From the point of view of efficiency, however, you are unlikely to do better than the compiler-generated implementations by coding these features <NOBR>yourself.<SCRIPT>create_link(43);</SCRIPT>
</NOBR></P>
<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./MI23_FR.HTM" TARGET="_top">Item 23: Consider alternative libraries</A> &nbsp;&nbsp;<BR>&nbsp;&nbsp;Continue to <A HREF="./MTECH_FR.HTM" TARGET="_top">Techniques</A></FONT></DIV>

</BODY>
</HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -