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

📄 mi32.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 HTM
📖 第 1 页 / 共 2 页
字号:
In other words, this is <NOBR>okay,<SCRIPT>create_link(20);</SCRIPT>
</NOBR></P>
<A NAME="46159"></A>
<UL><PRE>
class string {                    // from the standard C++ library
public:
  ~string();
};
<A NAME="46160"></A>
class B { ... };                  // no data members with dtors,
                                  // no virtual dtor needed
</PRE>
</UL><A NAME="46169"></A>
<A NAME="dingp21"></A><P><A NAME="dingp21"></A>but if a new class is derived from <CODE>B</CODE>, things <NOBR>change:<SCRIPT>create_link(21);</SCRIPT>
</NOBR></P>
<A NAME="46168"></A>
<UL><PRE>class D: public B {
  string name;                    // NOW ~B needs to be virtual
};
</PRE>
</UL><A NAME="46156"></A>
<P><A NAME="dingp22"></A>
Again, a small change to the way <CODE>B</CODE> is used (here, the addition of a derived class that contains a member with a destructor) may necessitate extensive recompilation and relinking by clients. But small changes in software should have small impacts on systems. This design fails that <NOBR>test.<SCRIPT>create_link(22);</SCRIPT>
</NOBR></P><A NAME="46180"></A>
<P><A NAME="dingp23"></A>
The same author <NOBR>writes:<SCRIPT>create_link(23);</SCRIPT>
</NOBR></P><A NAME="46183"></A>
<A NAME="dingp24"></A><BLOCKQUOTE>If a multiple inheritance hierarchy has any destructors, every base class should have a virtual destructor.<SCRIPT>create_link(24);</SCRIPT>
</BLOCKQUOTE>
<A NAME="46181"></A>
<P><A NAME="dingp25"></A>
In all these quotations, note the present-tense thinking. How do clients manipulate pointers <I>now</I>? What class members have destructors <I>now</I>? What classes in the hierarchy have destructors <I>now</I>?<SCRIPT>create_link(25);</SCRIPT>
</P><A NAME="46187"></A>
<A NAME="p256"></A><P><A NAME="dingp26"></A>
Future-tense thinking is quite different. Instead of asking how a class is used now, it asks how the class is <I>designed</I> to be used. Future-tense thinking says, if a class is <I>designed</I> to be used as a base class (even if it's not used as one now), it should have a virtual destructor (see <a href="../EC/EI14_FR.HTM#223029" TARGET="_top">Item E14</A>). Such classes behave correctly both now and in the future, and they don't affect other library clients when new classes derive from them. (At least, they have no effect as far as their destructor is concerned. If additional changes to the class are required, other clients may be <NOBR>affected.)<SCRIPT>create_link(26);</SCRIPT>
</NOBR></P><A NAME="46188"></A>
<P><A NAME="dingp27"></A>
A commercial class library (one that predates the <CODE>string</CODE> specification in the C++ library standard) contains a string class with no virtual destructor. The vendor's <NOBR>explanation?<SCRIPT>create_link(27);</SCRIPT>
</NOBR></P><A NAME="46193"></A>
<A NAME="dingp28"></A><BLOCKQUOTE>We didn't make the destructor virtual, because we didn't want <CODE>String</CODE> to have a vtbl. We have no intention of ever having a <CODE>String*</CODE>, so this is not a problem. We are well aware of the difficulties this could cause.<SCRIPT>create_link(28);</SCRIPT>
</BLOCKQUOTE>
<A NAME="46191"></A>
<P><A NAME="dingp29"></A>
Is this present-tense or future-tense <NOBR>thinking?<SCRIPT>create_link(29);</SCRIPT>
</NOBR></P><A NAME="46186"></A>
<P><A NAME="dingp30"></A>
Certainly the vtbl issue is a legitimate technical concern (see <a href="./MI24_FR.HTM#41284" TARGET="_top">Item 24</A> and <a href="../EC/EI14_FR.HTM#223029" TARGET="_top">Item E14</A>). The implementation of most <CODE>String</CODE> classes contains only a single <CODE>char*</CODE> pointer inside each <CODE>String</CODE> object, so adding a vptr to each <CODE>String</CODE> would double the size of those objects. It is easy to understand why a vendor would be unwilling to do that, especially for a highly visible, heavily used class like <CODE>String</CODE>. The performance of such a class might easily fall within the 20% of a program that makes a difference (see <a href="./MI16_FR.HTM#40995" TARGET="_top">Item 16</A>).<SCRIPT>create_link(30);</SCRIPT>
</P><A NAME="52877"></A>
<P><A NAME="dingp31"></A>
Still, the total memory devoted to a string object &#151; the memory for the object itself plus the heap memory needed to hold the string's value &#151; is typically much greater than just the space needed to hold a <CODE>char*</CODE> pointer. From this perspective, the overhead imposed by a vptr is less significant. Nevertheless, it is a legitimate technical consideration. (Certainly the <NOBR><FONT COLOR="#FF0000" SIZE="-2"><B>&deg;</B></FONT><A HREF="http://www.awl.com/cseng/cgi-bin/cdquery.pl?name=committee" onMouseOver="self.status='ISO/ANSI Standardization Committee Home Page'; return true" onMouseOut="self.status = self.defaultStatus" target="_top">ISO/ANSI</NOBR> standardization committee</A> seems to think so: the standard <CODE>string</CODE> type has a nonvirtual <NOBR>destructor.)<SCRIPT>create_link(31);</SCRIPT>
</NOBR></P><A NAME="46179"></A>
<P><A NAME="dingp32"></A>
Somewhat more troubling is the vendor's remark, "We have no intention of ever having a <CODE>String*</CODE>, so this is not a problem." That may be true, but their <CODE>String</CODE> class is part of a library they make available to <i>thousands</i> of developers. That's a lot of developers, each with a different level of experience with C++, each doing something unique. Do those developers understand the consequences of there being no virtual destructor in <CODE>String</CODE>? Are they likely to know that because <CODE>String</CODE> has no virtual destructor, deriving new classes from <CODE>String</CODE> is a high-risk venture? Is this vendor confident their clients will understand that in the absence of a virtual destructor, deleting objects through <CODE>String*</CODE> pointers will not work properly and RTTI operations <A NAME="p257"></A>on pointers and references to <CODE>String</CODE>s may return incorrect information? Is this class easy to use correctly and hard to use <NOBR>incorrectly?<SCRIPT>create_link(32);</SCRIPT>
</NOBR></P><A NAME="46245"></A>
<P><A NAME="dingp33"></A>
This vendor should provide documentation for its <CODE>String</CODE> class that makes clear the class is not designed for derivation, but what if programmers overlook the caveat or flat-out fail to read the <NOBR>documentation?<SCRIPT>create_link(33);</SCRIPT>
</NOBR></P><A NAME="46469"></A>
<P><A NAME="dingp34"></A>
An alternative would be to use C++ itself to prohibit derivation. <a href="./MI26_FR.HTM#5350" TARGET="_top">Item 26</A> describes how to do this by limiting object creation to the heap and then using <CODE>auto_ptr</CODE> objects to manipulate the heap objects. The interface for <CODE>String</CODE> creation would then be both unconventional and inconvenient, requiring <NOBR>this,<SCRIPT>create_link(34);</SCRIPT>
</NOBR></P>
<A NAME="46270"></A>
<UL><PRE>auto_ptr&lt;String&gt; ps(String::makeString("Future tense C++"));
<A NAME="60952"></A>
...                                 // treat ps as a pointer to
                                    // a String object, but don't
                                    // worry about deleting it
</PRE>
</UL><A NAME="46271"></A>
instead of this,
<A NAME="46272"></A>
<UL><PRE>String s("Future tense C++");
</PRE>
</UL><A NAME="46273"></A>
<P><A NAME="dingp35"></A>but perhaps the reduction in the risk of improperly behaving derived classes would be worth the syntactic inconvenience. (For <CODE>String</CODE>, this is unlikely to be the case, but for other classes, the trade-off might well be worth <NOBR>it.)<SCRIPT>create_link(35);</SCRIPT>
</NOBR></P><A NAME="46276"></A>
<P><A NAME="dingp36"></A>
There is a need, of course, for present-tense thinking. The software you're developing has to work with current compilers; you can't afford to wait until the latest language features are implemented. It has to run on the hardware you currently support and it must do so under configurations your clients have available; you can't force your customers to upgrade their systems or modify their operating environment. It has to offer acceptable performance now; promises of smaller, faster programs some years down the line don't generally warm the cockles of potential customers' hearts. And the software you're working on must be available "soon," which often means some time in the recent past. These are important constraints. You cannot ignore <NOBR>them.<SCRIPT>create_link(36);</SCRIPT>
</NOBR></P><A NAME="46303"></A>
<P><A NAME="dingp37"></A>
Future-tense thinking simply adds a few additional <NOBR>considerations:<SCRIPT>create_link(37);</SCRIPT>
</NOBR></P>
<UL><A NAME="46708"></A>
<A NAME="dingp38"></A><LI>Provide complete classes (see <a href="../EC/EI18_FR.HTM#17774" TARGET="_top">Item E18</A>), even if some parts aren't currently used. When new demands are made on your classes, you're less likely to have to go back and modify them.<SCRIPT>create_link(38);</SCRIPT>

<A NAME="46709"></A>
<A NAME="dingp39"></A><LI><A NAME="p258"></A>Design your interfaces to facilitate common operations and prevent common errors (see <a href="../EC/EI46_FR.HTM#195225" TARGET="_top">Item E46</A>). Make the classes easy to use correctly, hard to use incorrectly. For example, prohibit copying and assignment for classes where those operations make no sense (see <a href="../EC/EI27_FR.HTM#6406" TARGET="_top">Item E27</A>). Prevent partial assignments (see <a href="./MI33_FR.HTM#10947" TARGET="_top">Item 33</A>).<SCRIPT>create_link(39);</SCRIPT>

<A NAME="46710"></A>
<A NAME="dingp40"></A><LI>If there is no great penalty for generalizing your code, generalize it. For example, if you are writing an algorithm for tree traversal, consider generalizing it to handle any kind of directed acyclic graph.<SCRIPT>create_link(40);</SCRIPT>

</UL>

<A NAME="46310"></A>
<P><A NAME="dingp41"></A>
Future tense thinking increases the reusability of the code you write, enhances its maintainability, makes it more robust, and facilitates graceful change in an environment where change is a certainty. It must be balanced against present-tense constraints. Too many programmers focus exclusively on current needs, however, and in doing so they sacrifice the long-term viability of the software they design and implement. Be different. Be a renegade. Program in the future <NOBR>tense.<SCRIPT>create_link(41);</SCRIPT>
</NOBR></P>

<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./MMISC_FR.HTM" TARGET="_top">Miscellany</A> &nbsp;&nbsp;<BR>&nbsp;&nbsp;Continue to <A HREF="./MI33_FR.HTM" TARGET="_top">Item 33: Make non-leaf classes abstract</A></FONT></DIV>
</BODY>
</HTML>

⌨️ 快捷键说明

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