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

📄 ch04.htm

📁 c++语言操作手册
💻 HTM
📖 第 1 页 / 共 5 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"><HTML><HEAD>	<META NAME="Author" Content="Steph Mineart">	<META HTTP-EQUIV="Content-Type" CONTENT="text/html;CHARSET=iso-8859-1">	<TITLE>ANSI/ISO C++ Professional Programmer's Handbook - 4 - Special Member Functions: Default Constructor, Copy Constructor, Destructor, And Assignment Operator </TITLE>	<link rel="stylesheet"  TYPE="text/css" href="/includes/stylesheets/ebooks.css"></head><BODY TEXT="#000000" BGCOLOR="#FFFFFF"><CENTER><H1><img src="/publishers/que/series/professional/0789720221/button/que.gif" WIDTH="171" HEIGHT="66" ALIGN="BOTTOM" BORDER="0"><BR>ANSI/ISO C++ Professional Programmer's Handbook</H1></CENTER><CENTER>  <P><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>   <HR></CENTER><H1 align="center">4</H1><h1 align="center"> Special Member Functions: Default Constructor, Copy Constructor,   Destructor, And Assignment Operator</h1><address>by Danny Kale</address><ul>  <li><a href="#Heading1"> Introduction</a>   <li><a href="#Heading2">Constructors</a>     <ul>      <li><a href="#Heading3">Calling An Object's Member Function From Its Constructor</a>       <li><a href="#Heading4">Trivial Constructors</a>       <li><a href="#Heading5">Avoid Reduplicating Identical Pieces Of Constructors'         Code</a>       <li><a href="#Heading6">Is A Default Constructor Always Necessary?</a>       <li><a href="#Heading7">Eligibility For STL Containment</a>       <li><a href="#Heading8">When Are Default Constructors Undesirable?</a>       <li><a href="#Heading9"> Constructors Of Fundamental Types</a>       <li><a href="#Heading10">explicit Constructors</a>       <li><a href="#Heading11">Blocking Undesirable Object Instantiation</a>       <li><a href="#Heading12">Using Member Initialization Lists</a>       <li><a href="#Heading13">The Exception Specification Of An Implicitly-Declared         Default Constructor </a>     </ul>  <li><a href="#Heading14">Copy Constructor</a>     <ul>      <li><a href="#Heading15"> Implicitly-Defined Copy Constructors</a>       <li><a href="#Heading16">Implementation-Required Initializations</a>     </ul>  <li><a href="#Heading17">Simulating Virtual Constructors</a>     <ul>      <li><a href="#Heading18">Covariance of Virtual Member Functions</a>     </ul>  <li><a href="#Heading19">Assignment Operator</a>     <ul>      <li><a href="#Heading20">Implicitly-Defined Assignment Operator</a>       <li><a href="#Heading21">Simulating Inheritance Of Assignment Operator</a>     </ul>  <li><a href="#Heading22"> When Are User-Written Copy Constructors And Assignment     Operators Needed?</a>   <li><a href="#Heading23">Implementing Copy Constructor And Assignment Operator</a>   <li><a href="#Heading24">Blocking Object Copying</a>   <li><a href="#Heading25">Destructors</a>     <ul>      <li><a href="#Heading26"> Explicit Destructor Invocation</a>       <li><a href="#Heading27"> Pseudo Destructors</a>       <li><a href="#Heading28"> Pure Virtual Destructors</a>     </ul>  <li><a href="#Heading29">Constructors And Destructors Should Be Minimal</a>   <li><a href="#Heading30">Conclusions</a> </ul><hr size=4><h2><a name="Heading1"> Introduction</a></h2><p>Objects are the fundamental unit of abstraction in object-oriented programming.   An object, in the broader sense, is a region of memory storage. Class objects   have properties that are determined when the object is created. Conceptually,   every class object has four <i>special member functions</i>: default constructor,   copy constructor, assignment operator, and destructor. If these members are   not explicitly declared by the programmer, the implementation implicitly declares   them. This chapter surveys the semantics of the special member functions and   their role in class design and implementation. This chapter also examines several   techniques and guidelines for effective usage of the special member functions. </p><h2> <a name="Heading2">Constructors</a></h2><p>A constructor is used to initialize an object. A default constructor is one   that can be invoked without any arguments. If there is no user-declared constructor   for a class, and if the class does not contain <tt>const</tt> or reference data   members, the implementation implicitly declares a default constructor for it. </p><p>An implicitly-declared default constructor is an <tt>inline</tt> <tt>public</tt>   member of its class; it performs the initialization operations that are needed   by the implementation to create an object of this type. Note, however, that   these operations do not involve initialization of user-declared data members   or allocation of memory from the free store. For example</p><pre><tt>class C</tt><tt>{</tt><tt>private:</tt><tt>  int n;</tt><tt>  char *p;</tt><tt>public:</tt><tt>  virtual ~C() {}</tt><tt>};</tt><tt>void f()</tt><tt>{</tt><tt>  C obj;  // 1 implicitly-defined constructor is invoked</tt><tt>}</tt></pre><p>The programmer did not declare a constructor in class <tt>C</tt> -- an implicit   default constructor was declared and defined by the implementation in order   to create an instance of class <tt>C</tt> in the line numbered 1. The synthesized   constructor does not initialize the data members <tt>n</tt> and <tt>p</tt>,   nor does it allocate memory for the latter. These data members have an indeterminate   value after <tt>obj</tt> has been constructed. </p><p>This is because the synthesized default constructor performs only the initialization   operations that are required by the implementation -- not the programmer --   to construct an object. In this case, <tt>C</tt> is a polymorphic class. An   object of this type contains a pointer to the virtual function table of its   class. The virtual pointer is initialized by the implicitly-defined constructor. </p><p>Other implementation-required operations that are performed by implicitly-defined   constructors are the invocation of a base class constructor and the invocation   of the constructor of embedded objects. The implementation does not declare   a constructor for a class if the programmer has defined one. For example</p><pre><tt>class C</tt><tt>{</tt><tt>private:</tt><tt>  int n;</tt><tt>  char *p;</tt><tt>public:</tt><tt>  C() : n(0), p(NULL) {} </tt><tt>  virtual ~C() {}</tt><tt>};</tt><tt>void f2()</tt><tt>{</tt><tt>  C obj;  // 1 user-defined constructor is invoked</tt><tt>}</tt></pre><p>Now the data members of the object <tt>obj</tt> are initialized because the   user-defined constructor was invoked to create it. Note, however, that the user-defined   constructor only initializes the data members <tt>n</tt> and <tt>p</tt>. Obviously,   the virtual pointer must have been initialized as well -- otherwise, the program   will be ill-formed. But when did the initialization of the virtual pointer take   place? The compiler augments the user-defined constructor with additional code,   which is inserted into the constructor's body before any user-written code,   and performs the necessary initialization of the virtual pointer.</p><h3> <a name="Heading3">Calling An Object's Member Function From Its Constructor</a></h3><p>Because the virtual pointer is initialized in the constructor before any user-written   code, it is safe to call member functions (both virtual and nonvirtual) of an   object from its constructor. It is guaranteed that the invoked virtual is the   one that is defined in the current object (or of the base class, if it has not   been overridden in the current object). However, virtual member functions of   objects that are derived from the one whose constructor is executing are not   called. For example</p><pre><tt>class A</tt><tt>{</tt><tt>public:</tt><tt>  virtual void f() {}</tt><tt>  virtual void g() {}</tt><tt>};</tt><tt>class B: public  A</tt><tt>{</tt><tt>public:</tt><tt>  void f () {} // overriding A::f()</tt><tt>  B()</tt><tt>  {</tt><tt>    f();   // calls B::f()</tt><tt>    g();  // g() was not overriden in B, therefore calling A::g()</tt><tt>  }</tt><tt>};</tt><tt>class C: public B</tt><tt>{</tt><tt>public:</tt><tt>  void f () {} //overriding B::f()</tt><tt> };</tt></pre><p>Please note that if the object's member functions refer to data members of   the object, it is the 'programmer's responsibility to initialize these data   members first -- most preferably with a <i>member-initialization list</i> (member-initialization   lists are discussed next). For example</p><pre><tt>class C</tt><tt>{</tt><tt>private:</tt><tt>  int n;</tt><tt>  int  getn() const { cout&lt;&lt;n&lt;&lt;endl; }</tt><tt>public:</tt><tt>  C(int j) : n(j) { getn(); } //Fine: n initialized before getn() is called</tt><tt>};</tt></pre><h3> <a name="Heading4">Trivial Constructors</a></h3><p>As you have observed, compilers synthesize a default constructor for every   class or struct, unless a constructor was already defined by the user. However,   in certain conditions, such a synthesized constructor is redundant:</p><pre><tt>class Empty {}; //class has no base classes, virtual member functions</tt><tt>                //or embedded objects</tt><tt>struct Person</tt><tt>{</tt><tt>  int age;</tt><tt>  char name[20];</tt><tt>  double salary;</tt><tt>};</tt><tt>int main()</tt><tt>{</tt><tt>  Empty e;</tt><tt>  Person p;</tt><tt>  p.age = 30;</tt><tt>  return 0;</tt><tt>}</tt></pre><p>An implementation can instantiate <tt>Empty</tt> and <tt>Person</tt> objects   without a constructor. In such cases, the explicitly-declared constructor is   said to be <i>trivial</i>, which means that the implementation does not need   it in order to create an instance of its class. A constructor is considered   trivial when all the following hold true:</p><ul>  <li>    <p> Its class has no virtual member functions and no virtual base classes.</p>  </li>  <p></p>  <li>    <p> All the direct base classes of the constructor's class have trivial constructors.</p>  </li>  <p></p>  <li>    <p> All the member objects in the constructor's class have trivial constructors.</p>  </li></ul><p></p><p>You can see that both <tt>Empty</tt> and <tt>Person</tt> fulfill these conditions;   therefore, each of them has a trivial constructor. The compiler suppresses the   automatic synthesis of a trivial constructor, thereby producing code that is   as efficient in terms of size and speed as that which is produced by a C compiler.</p><h3> <a name="Heading5">Avoid Reduplicating Identical Pieces Of Constructors'   Code</a></h3><p>It is very common to define a class that has more than one constructor. For   instance, a <tt>string</tt> class can define one constructor that takes <tt>const   char *</tt> as an argument, another that takes an argument of type <tt>size_t</tt>   to indicate the initial capacity of the string, and a default constructor.</p><pre><tt>class string</tt><tt>{</tt><tt>private:</tt><tt>  char * pc;</tt><tt>  size_t capacity;</tt><tt>  size_t length;</tt><tt>  enum { DEFAULT_SIZE = 32};</tt><tt>public:</tt><tt>  string(const char * s);</tt><tt>  string(size_t initial_capacity );</tt><tt>  string();</tt><tt>//...other member functions and overloaded operators</tt><tt>};</tt></pre><p>Each of the three constructors performs individual operations. Nonetheless,   some identical tasks -- such as allocating memory from the free store and initializing   it, or assigning the value of <tt>capacity</tt> to reflect the size of the allocated   storage -- are performed in every constructor. Instead of repeating identical   pieces of code in each of the constructors, it is better to move the recurring   code into a single nonpublic member function. This function is called by every   constructor. The results are shorter compilation time and easier future maintenance:</p><pre><tt>class string</tt><tt>{</tt><tt>private:</tt><tt>  char * pc;</tt><tt>  size_t capacity;</tt><tt>  size_t length;</tt><tt>  enum { DEFAULT_SIZE = 32};</tt>

⌨️ 快捷键说明

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