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

📄 index.html

📁 C程序员手册(英文)
💻 HTML
📖 第 1 页 / 共 5 页
字号:
<tt>}</tt>
</pre>
<p>Extensive amounts of legacy C++ code rely on the implicit conversion of constructors. 
  The C++ Standardization committee was aware of that. In order to not make existing 
  code break, the implicit conversion was retained. However, a new keyword, <tt>explicit</tt>, 
  was introduced to the languageto enable the programmer to block the implicit 
  conversion when it is undesirable. As a rule, a constructor that can be invoked 
  with a single argument needs to be declared <tt>explicit</tt>. When the implicit 
  type conversion is intentional and well behaved, the constructor can be used 
  as an implicit conversion operator.</p>
<h3> <a name="Heading11">Blocking Undesirable Object Instantiation</a></h3>
<p>Sometimes it might be useful to disable programmers from instantiating an object 
  of a certain class, for example, a class that is meant to be used only as a 
  base class for others. A <tt>protected</tt> constructor blocks creation of class 
  instances, yet it does so without disallowing derived objects' instantiation:</p>
<pre>
<tt>class CommonRoot</tt>
<tt>{</tt>
<tt>protected:</tt>
<tt>  CommonRoot(){}//no objects of this class should be instantiated</tt>
<tt>  virtual  ~CommonRoot ();</tt>
<tt>};</tt>
<tt>class Derived: public CommonRoot</tt>
<tt>{</tt>
<tt>public:</tt>
<tt>  Derived();</tt>
<tt>};</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt>  Derived d;   // OK, constructor of d has access to </tt>
<tt>               //any protected member in its base class</tt>
<tt>  CommonRoot cr;  //compilation error: attempt to </tt>
<tt>                  //access a protected member of CommonRoot</tt>
<tt>}</tt>
</pre>
<p>The same effect of blocking instantiation of a class can be achieved by declaring 
  pure virtual functions. However, these add runtime and space overhead. When 
  pure virtual functions aren't needed, you can use a <tt>protected</tt> constructor 
  instead.</p>
<h3> <a name="Heading12">Using Member Initialization Lists</a></h3>
<p>A constructor might have a member initialization (mem-initialization for short) 
  list that initializes the data members of the class. For example</p>
<pre>
<tt>class Cellphone //1: mem-init</tt>
<tt>{</tt>
<tt>private:</tt>
<tt>  long number;</tt>
<tt>  bool on;</tt>
<tt>public:</tt>
<tt>  Cellphone (long n, bool ison) : number(n), on(ison) {}</tt>
<tt>};</tt>
</pre>
<p>The constructor of <tt>Cellphone</tt> can also be written as follows:</p>
<pre>
<tt>Cellphone (long n, bool ison) //2 initialization within constructor's body</tt>
<tt>{</tt>
<tt>  number = n;</tt>
<tt>  on = ison;</tt>
<tt>}</tt>
</pre>
<p>There is no substantial difference between the two forms in the case of <tt>Cellphone</tt>'s 
  constructor. This is due to the way mem-initialization lists are processed by 
  the compiler. The compiler scans the mem-initialization list and inserts the 
  initialization code into the constructor's body before any user-written code. 
  Thus, the constructor in the first example is expanded by the compiler into 
  the constructor in the second example. Nonetheless, the choice between using 
  a mem-initialization list and initialization inside the constructor's body is 
  significant in the following four cases: </p>
<ul>
  <li>
    <p> Initialization of <tt>const</tt> members</p>
  </li>
  <p></p>
  <li>
    <p> Initialization of reference members</p>
  </li>
  <p></p>
  <li>
    <p> Passing arguments to a constructor of a base class or an embedded object</p>
  </li>
  <p></p>
  <li>
    <p> Initialization of member objects</p>
  </li>
</ul>
<p></p>
<p>In the first three cases, a mem-initialization list is mandatory; in the fourth 
  case, it is optional. Consider the concrete examples that are discussed in the 
  following paragraphs.'</p>
<h4> const Data Members</h4>
<p><tt>const</tt> data members of a class, including <tt>const</tt> members of 
  a base or embedded subobject, must be initialized in a mem-initialization list.</p>
<pre>
<tt>class Allocator</tt>
<tt>{</tt>
<tt>private:</tt>
<tt>  const int chunk_size;</tt>
<tt>public:</tt>
<tt>  Allocator(int size) : chunk_size(size) {}</tt>
<tt>};</tt>
</pre>
<h4> Reference Data Members</h4>
<p>A reference data member must be initialized by a mem-initialization list.</p>
<pre>
<tt>class Phone;</tt>
<tt>class Modem</tt>
<tt>{</tt>
<tt>private:</tt>
<tt>  Phone &amp; line;</tt>
<tt>public:</tt>
<tt>   Modem(Phone &amp; ln) : line(ln) {}</tt>
<tt>};</tt>
</pre>
<h4> Invoking A Constructor Of A Base Or A Member Object With Arguments</h4>
<p>When a constructor has to pass arguments to the constructor of its base class 
  or to the constructor of an embedded object, a mem-initializer must be used.</p>
<pre>
<tt>class base</tt>
<tt>{</tt>
<tt>private:</tt>
<tt>  int num1;</tt>
<tt>  char * text;</tt>
<tt>public:</tt>
<tt>  base(int n1, char * t) {num1 = n1; text = t; } //no default constructor</tt>
<tt>};</tt>
<tt>class derived : public base</tt>
<tt>{</tt>
<tt>private:</tt>
<tt>  char *buf;</tt>
<tt>public:</tt>
<tt>  derived (int n, char * t) : base(n, t) //pass arguments to base constructor </tt>
<tt>  { buf = (new char[100]);} </tt>
<tt>};</tt>
</pre>
<h4> Embedded Objects</h4>
<p>Consider the following example:</p>
<pre>
<tt>#include&lt;string&gt;</tt>
<tt>using std::string;</tt>
<tt>class Website</tt>
<tt>{</tt>
<tt>private:</tt>
<tt>  string URL</tt>
<tt>  unsigned int IP</tt>
<tt>public:</tt>
<tt>  Website()</tt>
<tt>  {</tt>
<tt>    URL = "";</tt>
<tt>    IP = 0;</tt>
<tt>  }</tt>
<tt>};</tt>
</pre>
<p>Class <tt>Website</tt> has an embedded object of type <tt>std::string</tt>. 
  The syntax rules of the language do not force the usage of mem-initialization 
  to initialize this member. However, the performance gain in choosing mem-initialization 
  over initialization inside the constructor's body is significant. Why? The initialization 
  inside the constructor's body is very inefficient because it requires the construction 
  of the member <tt>URL</tt>; a temporary <tt>std::string</tt> object is then 
  constructed from the value <tt>""</tt>, which is in turn assigned to <tt>URL</tt>. 
  Finally, the temporary object has to be destroyed. The use of a mem-initialization 
  list, on the other hand, avoids the creation and destruction of a temporary 
  object (the performance implications of mem-initialization lists are discussed 
  in further detail in Chapter 12, "Optimizing Your Code"). </p>
<h4> ""The Order Of A Mem-Initialization List Must Match The Order Of Class Member 
  Declarations</h4>
<p>Due to the performance difference between the two forms of initializing embedded 
  objects, some programmers use mem-initialization exclusively -- even for fundamental 
  types. It is important to note, however, that the order of the initialization 
  list has to match the order of declarations within the class. This is because 
  the compiler transforms the list so that it coincides with the order of the 
  declaration of the class members, regardless of the order specified by the programmer. 
  For example</p>
<pre>
<tt>class Website</tt>
<tt>{</tt>
<tt>private:</tt>
<tt>  string URL; //1</tt>
<tt>  unsigned int IP; //2</tt>
<tt>public:</tt>
<tt>  Website() : IP(0), URL("") {} // initialized in reverse order</tt>
<tt>};</tt>
</pre>
<p>In the mem-initialization list, the programmer first initializes the member 
  <tt>IP</tt>, and then <tt>URL</tt>, even though <tt>IP</tt> is declared after 
  <tt>URL</tt>. The compiler transforms the initialization list to the order of 
  the member declarations within the class. In this case, the reverse order is 
  harmless. When there are dependencies in the order of initialization list, however, 
  this transformation can cause unexpected surprises. For example</p>
<pre>
<tt>class string</tt>
<tt>{</tt>
<tt>private:</tt>
<tt>  char *buff;</tt>
<tt>  int capacity;</tt>
<tt>public:</tt>
<tt>  explicit string(int size) : </tt>
<tt>  capacity(size), buff (new char [capacity]) {} undefined behavior</tt>
<tt>};</tt>
</pre>
<p>The mem-initialization list in the constructor of <tt>string</tt> does not 
  follow the order of declaration of <tt>string</tt>'s members. Consequently, 
  the compiler transforms the list into</p>
<pre>
<tt>explicit string(int size) : </tt>
<tt>buff  (new char [capacity]), capacity(size) {} </tt>
</pre>
<p>The member <tt>capacity</tt> specifies the number of bytes that <tt>new</tt> 
  has to allocate; but it has not been initialized. The results in this case are 
  undefined. There are two ways to avert this pitfall: Change the order of member 
  declarations so that <tt>capacity</tt> is declared before <tt>buff</tt>, or 
  move the initialization of <tt>buff</tt> into the constructor's body.</p>
<h3> <a name="Heading13">The Exception Specification Of An Implicitly-Declared 
  Default Constructor </a></h3>
<p>An implicitly-declared default constructor has an <i>exception specification</i> 
  (exception specifications are discussed in Chapter 6, ""Exception Handling""). 
  The exception specification of an implicitly-declared default constructor contains 
  all the exceptions of every other special member function that the constructor 
  invokes directly. For example</p>
<pre>
<tt>struct A </tt>
<tt>{</tt>
<tt>  A(); //can throw any type of exception</tt>
<tt>};</tt>
<tt>struct B </tt>
<tt>{</tt>
<tt>  B() throw(); //not allowed to throw any exceptions</tt>
<tt>};</tt>
<tt>struct C : public B</tt>
<tt>{</tt>
<tt>  //implicitly-declared C::C() throw;</tt>
<tt>}</tt>
<tt>struct D: public A, public B </tt>
<tt>{</tt>
<tt>  //implicitly-declared D::D(); </tt>
<tt>};</tt>
</pre>
<p>The implicitly-declared constructor in class <tt>C</tt> is not allowed to throw 
  any exceptions because it directly invokes the constructor of class <tt>B</tt>, 
  which is not allowed to throw any exceptions either. On the other hand, the 
  implicitly-declared constructor in class <tt>D</tt> is allowed to throw any 
  type of exception because it directly invokes the constructors of classes <tt>A</tt> 
  and <tt>B</tt>. Since the constructor of class <tt>A</tt> is allowed to throw 
  any type of exception, <tt>D</tt>'s implicitly-declared constructor has a matching 
  exception specification. In other words, <tt>D</tt>'s implicitly-declared constructor 
  allows all exceptions if any function that it directly invokes allows all exceptions; 
  it allows no exceptions if every function that it directly invokes allows no 
  exceptions either. As you will see soon, the same rules apply to the exception 
  specifications of other implicitly-declared special member functions. </p>
<h2> <a name="Heading14">Copy Constructor</a></h2>
<p>A <i>copy constructor</i> is used to initialize its object with another object. 
  A constructor of a class <tt>C</tt> is a copy constructor if its first argument 
  is of type <tt>C&amp;</tt>, <tt>const C&amp;</tt>, <tt>volatile C&amp;</tt>, 
  or <tt>const volatile C&amp;</tt>, and if there are no additional arguments 
  or if all other arguments have default values. If there is no user-defined copy 
  constructor for a class, the implementation implicitly declares one. An implicitly-declared 
  copy constructor is an <tt>inline public</tt> member of its class, and it has 
  the form</p>
<pre>
<tt>C::C(const C&amp;);</tt>
</pre>
<p>if each base class of <tt>C</tt> has a copy constructor whose first argument 
  is a reference to a <tt>const</tt> object of the base class type, and if all 
  the nonstatic embedded objects in <tt>C</tt> also have a copy constructor that 
  takes a reference to a <tt>const</tt> object of their type. Otherwise, the implicitly-declared 
  copy constructor is of the following type:</p>
<pre>
<tt>C::C(C&amp;);</tt>
</pre>
<p>An implicitly-declared copy constructor has an exception specification. The 
  exception specification contains all the exceptions that might be thrown by 
  other special functions that the copy constructor invokes directly.</p>
<h3> <a name="Heading15"> Implicitly-Defined Copy Constructors</a></h3>

⌨️ 快捷键说明

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