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

📄 mi4.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 HTM
📖 第 1 页 / 共 2 页
字号:
// EquipmentPiece objects; see <a href="./MI8_FR.HTM#33985" TARGET="_top">Item 8</A> for details on
// the operator <NOBR>new[]</NOBR> function
void *rawMemory =
  operator <NOBR>new[]</NOBR>(10*sizeof(EquipmentPiece));
</PRE>
</UL><A NAME="40116"></A>
<UL><PRE>// make bestPieces point to it so it can be treated as an
// EquipmentPiece array
EquipmentPiece *bestPieces =
  static_cast&lt;EquipmentPiece*&gt;(rawMemory);
</PRE>
</UL><A NAME="40085"></A>
<UL><PRE>// construct the EquipmentPiece objects in the memory
// using "placement new" (see <a href="./MI8_FR.HTM#33985" TARGET="_top">Item 8</A>)
for (int i = 0; i &lt; 10; ++i)
  new (&amp;bestPieces[i]) EquipmentPiece( <I>ID Number</I> );
</PRE>
</UL><A NAME="40025"></A>
<P><A NAME="dingp13"></A>
Notice that you still have to provide a constructor argument for each <CODE>EquipmentPiece</CODE> object. This technique (as well as the array-of-pointers idea) allows you to create arrays of objects when a class lacks a default constructor; it doesn't show you how to bypass required constructor arguments. There is no way to do that. If there were, it would defeat the purpose of constructors, which is to <I>guarantee</I> that objects are <NOBR>initialized.<SCRIPT>create_link(13);</SCRIPT>
</NOBR></p><A NAME="40095"></A>
<P><A NAME="dingp14"></A>
The downside to using placement <CODE>new</CODE>, aside from the fact that most programmers are unfamiliar with it (which will make maintenance more difficult), is that you must manually call destructors on the objects in the array when you want them to go out of existence, then you must manually deallocate the raw memory by calling <CODE>operator</CODE> <CODE><NOBR>delete[]</NOBR></CODE> (again, see <a href="./MI8_FR.HTM#33985" TARGET="_top">Item 8</A>):<SCRIPT>create_link(14);</SCRIPT>
</P>
<A NAME="40103"></A>
<UL><PRE>// destruct the objects in bestPieces in the inverse
// order in which they were constructed
for (int i = 9; i &gt;= 0; --i)
  bestPieces[i].~EquipmentPiece();
<A NAME="65638"></A>
// deallocate the raw memory
operator <NOBR>delete[]</NOBR>(rawMemory);</PRE>
</UL>
<A NAME="51627"></A>
<P><A NAME="dingp15"></A>
If you forget this requirement and use the normal array-deletion syntax, your program will behave unpredictably. That's because the result of deleting a pointer that didn't come from the <CODE>new</CODE> operator is undefined:
<A NAME="82073"></A><SCRIPT>create_link(15);</SCRIPT>
</P>
<UL><PRE>delete [] bestPieces;                    // undefined! bestPieces
                                         // didn't come from the new
                                         // operator</PRE>
</UL>
<A NAME="85028"></A>
<P><A NAME="dingp16"></A>
For more information on the <CODE>new</CODE> operator, placement <CODE>new</CODE> and how they interact with constructors and destructors, see <a href="./MI8_FR.HTM#33985" TARGET="_top">Item 8</A>.<SCRIPT>create_link(16);</SCRIPT>
</p><A NAME="85033"></A>
<A NAME="p22"></A><P><A NAME="dingp17"></A>
The second problem with classes lacking default constructors is that they are ineligible for use with many template-based container classes. That's because it's a common requirement for such templates that the type used to instantiate the template provide a default constructor. This requirement almost always grows out of the fact that inside the template, an array of the template parameter type is being created. For example, a template for an <CODE>Array</CODE> class might look something like this:
<A NAME="57398"></A><SCRIPT>create_link(17);</SCRIPT>
</P>
<UL><PRE>template&lt;class T&gt;
class Array {
public:
  Array(int size);
  ...
<A NAME="57403"></A>
private:
  T *data;
};
<A NAME="40164"></A>
template&lt;class T&gt;
Array&lt;T&gt;::Array(int size)
{
  data = new T[size];                    // calls T::T() for each
  ...                                    // element of the array
}</PRE>
</UL>
<A NAME="40171"></A>
<P><A NAME="dingp18"></A>
In most cases, careful template design can eliminate the need for a default constructor. For example, the standard <CODE>vector</CODE> template (which generates classes that act like extensible arrays) has no requirement that its type parameter have a default constructor. Unfortunately, many templates are designed in a manner that is anything but careful. That being the case, classes without default constructors will be incompatible with many templates. As C++ programmers learn more about template design, this problem should recede in significance. How long it will take for that to happen, however, is anyone's <NOBR>guess.<SCRIPT>create_link(18);</SCRIPT>
</NOBR></p><A NAME="85003"></A>
<P><A NAME="dingp19"></A>
The final consideration in the to-provide-a-default-constructor-or-not-to-provide-a-default-constructor dilemma has to do with virtual base classes (see <a href="../EC/EI43_FR.HTM#7778" TARGET="_top">Item E43</A>). Virtual base classes lacking default constructors are a pain to work with. That's because the arguments for virtual base class constructors must be provided by the most derived class of the object being constructed. As a result, a virtual base class lacking a default constructor requires that <I>all</I> classes derived from that class &#151; no matter how far removed &#151; must know about, understand the meaning of, and provide for the virtual base class's constructors' arguments. Authors of derived classes neither expect nor appreciate this <NOBR>requirement.<SCRIPT>create_link(19);</SCRIPT>
</NOBR></p><A NAME="85004"></A>
<P><A NAME="dingp20"></A>
Because of the restrictions imposed on classes lacking default constructors, some people believe <I>all</I> classes should have them, even if a <A NAME="p23"></A>default constructor doesn't have enough information to fully initialize objects of that class. For example, adherents to this philosophy might modify <CODE>EquipmentPiece</CODE> as <NOBR>follows:<SCRIPT>create_link(20);</SCRIPT>
</NOBR></p><A NAME="40234"></A>
<UL><PRE>class EquipmentPiece {
public:
  EquipmentPiece(  int IDNumber = UNSPECIFIED);
  ...
</PRE>
</UL><A NAME="65700"></A>
<UL><PRE>private:
  static const int   UNSPECIFIED;        // magic ID number value
                                         // meaning no ID was
};                                       // specified
</PRE>
</UL><A NAME="40232"></A>
<P><A NAME="dingp21"></A>
This allows <CODE>EquipmentPiece</CODE> objects to be created like <NOBR>this:<SCRIPT>create_link(21);</SCRIPT>
</NOBR></p><A NAME="40239"></A>
<UL><PRE>EquipmentPiece e;                         // now okay
</PRE>
</UL><A NAME="40240"></A>
<P><A NAME="dingp22"></A>
Such a transformation almost always complicates the other member functions of the class, because there is no longer any guarantee that the fields of an <CODE>EquipmentPiece</CODE> object have been meaningfully initialized. Assuming it makes no sense to have an <CODE>EquipmentPiece</CODE> without an ID field, most member functions must check to see if the ID is present. If it's not, they'll have to figure out how to stumble on anyway. Often it's not clear how to do that, and many implementations choose a solution that offers nothing but expediency: they throw an exception or they call a function that terminates the program. When that happens, it's difficult to argue that the overall quality of the software has been improved by including a default constructor in a class where none was <NOBR>warranted.<SCRIPT>create_link(22);</SCRIPT>
</NOBR></p><A NAME="40277"></A>
<P><A NAME="dingp23"></A>
Inclusion of meaningless default constructors affects the efficiency of classes, too. If member functions have to test to see if fields have truly been initialized, clients of those functions have to pay for the time those tests take. Furthermore, they have to pay for the code that goes into those tests, because that makes executables and libraries bigger. They also have to pay for the code that handles the cases where the tests fail. All those costs are avoided if a class's constructors ensure that all fields of an object are correctly initialized. Often default constructors can't offer that kind of assurance, so it's best to avoid them in classes where they make no sense. That places some limits on how such classes can be used, yes, but it also guarantees that when you do use such classes, you can expect that the objects they generate are fully initialized and are efficiently <NOBR>implemented.<SCRIPT>create_link(23);</SCRIPT>
</NOBR></p>

<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./MI3_FR.HTM" TARGET="_top">Item 3: Never treat arrays polymorphically</A> &nbsp;&nbsp;<BR>&nbsp;&nbsp;Continue to <A HREF="./MOPER_FR.HTM" TARGET="_top">Operators</A></FONT></DIV>

</BODY>
</HTML>

⌨️ 快捷键说明

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