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

📄 index.html

📁 C程序员手册(英文)
💻 HTML
📖 第 1 页 / 共 5 页
字号:
  the other by means of the first. For example</p>
<pre>
<tt>#include &lt;cstring&gt;</tt>
<tt>using namespace std;</tt>
<tt>class Person</tt>
<tt>{</tt>
<tt>private:</tt>
<tt>  int age;</tt>
<tt>  char * name;</tt>
<tt>public:</tt>
<tt>  int getAge () const { return age;}</tt>
<tt>  const char * getName() const { return name; }</tt>
<tt>  //...</tt>
<tt>  Person (const char * name = NULL, int age =0) {}</tt>
<tt>  Person &amp; operator= (const Person &amp; other);</tt>
<tt>  Person (const Person&amp; other);</tt>
<tt>};</tt>
<tt>Person &amp; Person::operator= (const Person &amp; other)</tt>
<tt>{</tt>
<tt>  if (&amp;other  !=  this) //guard from self assignment</tt>
<tt>  {</tt>
<tt>     size_t len = strlen( other.getName());</tt>
<tt>     if (strlen (getName() ) &lt; len)</tt>
<tt>     {</tt>
<tt>        delete [] name; //release current buffer</tt>
<tt>        name = new char [len+1];</tt>
<tt>     }</tt>
<tt>    strcpy(name, other.getName());</tt>
<tt>    age = other.getAge();</tt>
<tt>  }</tt>
<tt>  return *this;</tt>
<tt>}</tt>
<tt>Person::Person (const Person &amp; other)</tt>
<tt>{</tt>
<tt> *this=other; //OK, use user-defined assignment operator is invoked</tt>
<tt>}</tt>
</pre>
<h2> <a name="Heading24">Blocking Object Copying</a></h2>
<p>There are situations in which enabling the user to copy or assign a new value 
  to an object is undesirable. You can disable both by explicitly declaring the 
  assignment operator and copy constructor as <tt>private</tt>:</p>
<pre>
<tt>class NoCopy</tt>
<tt>{</tt>
<tt>private:</tt>
<tt>  NoCopy&amp;  operator = (const NoCopy&amp; other) { return *this; }</tt>
<tt>  NoCopy(const NoCopy&amp; other) {/*..*/}</tt>
<tt>public:</tt>
<tt>  NoCopy() {}</tt>
<tt>//...</tt>
<tt>};</tt>
<tt>void f()</tt>
<tt>{</tt>
<tt>  NoCopy nc;  // fine, default constructor called</tt>
<tt>  NoCopy nc2(nc);  //error; attempt to call a private copy constructor</tt>
<tt>  nc2 = nc; //also a compile time error; operator= is private</tt>
<tt>}</tt>
</pre>
<h2> <a name="Heading25">Destructors</a></h2>
<p>A destructor destroys an object of its class type. It takes no arguments and 
  has no return type (not even <tt>void</tt>). <tt>const</tt> and <tt>volatile</tt> 
  qualities are not applied on an object under destruction; therefore, destructors 
  can be invoked for <tt>const</tt>, <tt>volatile</tt>, or <tt>const volatile</tt> 
  objects. If there is no user-defined destructor for a class, the implementation 
  implicitly declares one. An implicitly-declared destructor is an <tt>inline 
  public</tt> member of its class and has an exception specification. The exception 
  specification contains all the exceptions that might be thrown by other special 
  functions that the destructor invokes directly.</p>
<p>A destructor is trivial if it is implicitly declared and if its entire direct 
  base classes and embedded objects have trivial destructors. Otherwise, the destructor 
  is nontrivial. A destructor invokes the destructors of the direct base classes 
  and member objects of its class. The invocation occurs in the reverse order 
  of their construction. All destructors are called with their qualified name, 
  ignoring any possible virtual overriding destructors in more derived classes. 
  For example</p>
<pre>
<tt>#include &lt;iostream&gt;</tt>
<tt>using namespace std;</tt>
<tt>class A</tt>
<tt>{</tt>
<tt>public:</tt>
<tt>  virtual ~A() { cout&lt;&lt;"destroying A"&lt;&lt;endl;}</tt>
<tt>};</tt>
<tt>class B: public A</tt>
<tt>{</tt>
<tt>public:</tt>
<tt>  ~B() { cout&lt;&lt;"destroying B"&lt;&lt;endl;}</tt>
<tt>};</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt>  B b;</tt>
<tt>  return 0;</tt>
<tt>};</tt>
</pre>
<p>This program displays</p>
<pre>
<tt>destroying B</tt>
<tt>destroying A </tt>
</pre>
<p>This is because the compiler transforms the user-defined destructor of class 
  <tt>B</tt> into</p>
<pre>
<tt>~B() </tt>
<tt>{</tt>
<tt>    //user-written code below</tt>
<tt>  cout&lt;&lt;"destroying B"&lt;&lt;endl; </tt>
<tt>    //pseudo C++ code inserted by the compiler below</tt>
<tt>  this-&gt;A::~A(); // destructor called using its qualified name</tt>
<tt>}</tt>
</pre>
<p>Although the destructor of class <tt>A</tt> is virtual, the qualified call 
  that is inserted into the destructor of class <tt>B</tt> is resolved statically 
  (calling a function with a qualified name bypasses the dynamic binding mechanism).</p>
<h3> <a name="Heading26"> Explicit Destructor Invocation</a></h3>
<p>Destructors are invoked implicitly in the following cases:</p>
<ul>
  <li>
    <p> For static objects at program termination</p>
  </li>
  <p></p>
  <li>
    <p> For local objects when the block in which the object is created exits</p>
  </li>
  <p></p>
  <li>
    <p> For a temporary object when the lifetime of the temporary object ends</p>
  </li>
  <p></p>
  <li>
    <p> For objects allocated on the free store using <tt>new</tt>, through the 
      use of <tt>delete</tt></p>
  </li>
  <p></p>
  <li>
    <p> During stack unwinding that results from an exception</p>
  </li>
</ul>
<p></p>
<p>A destructor can also be invoked explicitly. For example:</p>
<pre>
<tt>class C</tt>
<tt>{</tt>
<tt>public:</tt>
<tt>~C() {}</tt>
<tt>};</tt>
<tt>void destroy(C&amp; c)</tt>
<tt>{</tt>
<tt>  c.C::~C(); //explicit destructor activation</tt>
<tt>}</tt>
</pre>
<p>A destructor can also be explicitly invoked from within a member function of 
  its object:</p>
<pre>
<tt>void C::destroy()</tt>
<tt>{</tt>
<tt>  this-&gt;C::~C();</tt>
<tt>}</tt>
</pre>
<p>In particular, explicit destructor invocation is necessary for objects that 
  were created by the <tt>placement new</tt> operator (<tt>placement new</tt> 
  is discussed in Chapter 11, "Memory Management").</p>
<h3> <a name="Heading27"> Pseudo Destructors</a></h3>
<p>Fundamental types have constructors, as you have seen. In addition, fundamental 
  types also have a <i>pseudo destructor</i>. A pseudo destructor is a syntactic 
  construct whose sole purpose is to satisfy the need of generic algorithms and 
  containers. It is a no-op code that has no real effect on its object. If you 
  examine the assembly code that your compiler produces for a pseudo destructor 
  invocation, you might discover that the compiler simply ignored it. A pseudo 
  destructor invocation is shown in the following example:</p>
<pre>
<tt>typedef int N;</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt>  N i = 0;</tt>
<tt>  i.N::~N(); //pseudo destructor invocation</tt>
<tt>  i = 1; //i  was not affected by the invocation of the pseudo destructor</tt>
<tt>  return 0;</tt>
<tt>}</tt>
</pre>
<p>The variable <tt>i</tt> is defined and initialized. In the following statement, 
  the pseudo destructor of the non-class type <tt>N</tt> is explicitly invoked 
  but it has no effect on its object. Like the constructors of fundamental types, 
  pseudo destructors enable the user to write code without having to know if a 
  destructor actually exists for a given type.</p>
<h3> <a name="Heading28"> Pure Virtual Destructors</a></h3>
<p>Unlike ordinary member functions, a virtual destructor is not overridden when 
  it is redefined in a derived class. Rather, it is extended. The lower-most destructor 
  first invokes the destructor of its base class; only then is it executed. Consequently, 
  when you try to declare a pure virtual destructor, you might encounter compilation 
  errors, or worse -- a runtime crash. In this respect, pure virtual destructors 
  are exceptional among pure virtual functions -- they have to be defined. You 
  can refrain from declaring a destructor with the pure specifier, making it only 
  virtual. However, this is an unnecessary design compromise. You can enjoy both 
  worlds by forcing an interface whose members are all pure virtual, including 
  the destructor -- and all this without experiencing runtime crashes. How is 
  it done?</p>
<p>First, the abstract class contains only a declaration of a pure virtual destructor:</p>
<pre>
<tt>class Interface</tt>
<tt>{</tt>
<tt>public:</tt>
<tt>  virtual void Open() = 0;</tt>
<tt>  virtual ~Interface() = 0;</tt>
<tt>};</tt>
</pre>
<p>Somewhere outside the class declaration, the pure virtual destructor has to 
  be defined as follows:</p>
<pre>
<tt>Interface::~Interface()</tt>
<tt>{} //definition of a pure virtual destructor; should always be empty</tt>
</pre>
<h2> <a name="Heading29">Constructors And Destructors Should Be Minimal</a></h2>
<p>When you are designing a class, remember that it might serve as a base for 
  other subclasses. It can also be used as a member object in a larger class. 
  As opposed to ordinary member functions, which can be overridden or simply not 
  called, the base class constructor and destructor are automatically invoked. 
  It is not a good idea to force users of a derived and embedded object to pay 
  for what they do not need, but are forced to accept. In other words, constructors 
  and destructors should contain nothing but the minimal functionality needed 
  to construct an object and destroy it. A concrete example can demonstrate that: 
  A <tt>string</tt> class that supports serialization should not open/create a 
  file in its constructor. Such operations need to be left to a dedicated member 
  function. When a new derived class -- such as <tt>ShortString</tt>, which holds 
  a fixed length string -- is created, its constructor is not forced to perform 
  superfluous file I/O that is imposed by the constructor of its base class.</p>
<h2> <a name="Heading30">Conclusions</a></h2>
<p>The constructor, copy constructor, assignment operator, and destructor automate 
  most of the tedium that is associated with creating, copying, and destroying 
  objects. The symmetry between a constructor and a destructor in C++ is rare 
  among object-oriented programming languages, and it serves as the basis for 
  advanced design idioms (as you will see in the next chapter, "Object Oriented 
  Programming and Design").</p>
<p>Each C++ object possesses the four member functions, which can be declared 
  by the programmer or declared implicitly by the implementation. An implicitly-declared 
  special member function can be trivial, which means that the implementation 
  does not have to define it. The synthesized special member functions perform 
  only operations that are required by the implementation. User-written special 
  member functions are automatically augmented by the compiler -- to ensure the 
  proper initialization of base and embedded subobjects -- and the virtual pointer. 
  Fundamental types have constructors and pseudo destructors, which facilitate 
  generic programming.</p>
<p>In many cases, the synthesized special member functions do the "right thing". 
  When the default behavior is unfitted, the programmer has to define one or more 
  of the special functions explicitly. Often, however, the need for user-written 
  code derives from combining low-level data structures with a high-level interface, 
  and might indicate a design flaw. Declaring a constructor <tt>explicit</tt> 
  ensures that it will not serve as an implicit conversion operator.</p>
<p>A mem-initialization list is necessary for the initialization of <tt>const</tt> 
  and reference data members, as well as to pass arguments to a base or embedded 
  subobject. In all other cases, a mem-initialization list is optional but can 
  enhance performance. Constructors and assignment operators can be used in several 
  ways to control instantiation and copying of objects. Destructors can be invoked 
  explicitly. Destructors that are declared pure virtual have to be defined.</p>
<CENTER>
<P>
<HR>
  <A HREF="/publishers/que/series/professional/0789720221/index.htm"><img src="/publishers/que/series/professional/0789720221/button/contents.gif" WIDTH="128"
HEIGHT="28" ALIGN="BOTTOM" ALT="Contents" BORDER="0"></A> <BR>
<BR>
<BR>
<p></P>

<P>&#169; <A HREF="/publishers/que/series/professional/0789720221/copy.htm">Copyright 1999</A>, Macmillan Computer Publishing. All
rights reserved.</p>
</CENTER>


</BODY>

</HTML>

⌨️ 快捷键说明

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