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

📄 index.html

📁 C程序员手册(英文)
💻 HTML
📖 第 1 页 / 共 5 页
字号:
<tt>  // the following function is called by every user-defined constructor</tt>
<tt>  void init( size_t cap = DEFAULT_SIZE);   </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>
<tt>void string::init( size_t cap)</tt>
<tt>{</tt>
<tt>  pc = new char[cap];</tt>
<tt>  capacity = cap;</tt>
<tt>}</tt>
<tt>string::string(const char * s)</tt>
<tt>{</tt>
<tt>  size_t size = strlen (s);</tt>
<tt>  init(size + 1); //make room for null terminating character</tt>
<tt>  length = size;</tt>
<tt>  strcpy(pc, s);</tt>
<tt>}</tt>
<tt>string::string(size_t initial_capacity )</tt>
<tt>{</tt>
<tt>  init(initial_capacity);</tt>
<tt>  length=0;</tt>
<tt>}</tt>
<tt>string::string()</tt>
<tt>{</tt>
<tt>  init();</tt>
<tt>  length = 0;</tt>
<tt>}</tt>
</pre>
<h3> <a name="Heading6">Is A Default Constructor Always Necessary?</a></h3>
<p>A class might have no default constructor. For example</p>
<pre>
<tt>class File</tt>
<tt>{</tt>
<tt>private:</tt>
<tt>  string path;</tt>
<tt>  int mode;</tt>
<tt>public:</tt>
<tt>  File(const string&amp; file_path, int open_mode);</tt>
<tt>  ~File();</tt>
<tt>};</tt>
</pre>
<p>Class <tt>File</tt> has a user-defined constructor that takes two arguments. 
  The existence of a user-defined constructor blocks the synthesis of an implicitly-declared 
  default constructor. Because the programmer did not define a default constructor 
  either, class <tt>File</tt> does not have a default constructor. A class with 
  no default constructor limits its users to a narrower set of allowed uses. For 
  instance, when an array of objects is instantiated, the default constructor 
  -- and only the default constructor -- of each array member is invoked. Therefore, 
  you cannot instantiate arrays thereof unless you use a complete initialization 
  list: </p>
<pre>
<tt>File folder1[10]; //error, array requires default constructor</tt>
<tt>File folder2[2] = { File("f1", 1)}; //error, f2[1] still requires</tt>
<tt>                                    //a default constructor</tt>
<tt>File folder3[3] = { File("f1", 1), File("f2",2), File("f3",3) }; //OK, </tt>
<tt>                                                    //fully initialized array</tt>
<tt>Similar difficulties arise when you attempt to store objects that have no default constructor in STL containers:#include &lt;vector&gt;</tt>
<tt>using namespace std;</tt>
<tt>void f()</tt>
<tt>{</tt>
<tt>  vector &lt;File&gt; fv(10); //error, File has no default constructor</tt>
<tt>  vector &lt;File&gt; v; //OK</tt>
<tt>  v.push_back(File("db.dat", 1)); //OK</tt>
<tt>  v.resize(10); //error, File has no default constructor</tt>
<tt>  v.resize(10, File("f2",2)); //OK</tt>
<tt>}</tt>
</pre>
<p> Was the lack of a default constructor in class <tt>File</tt> intentional? 
  Maybe. Perhaps the implementer considered an array of <tt>File</tt> objects 
  undesirable because each object in the array needs to somehow acquire its path 
  and open mode. However, the lack of a default constructor </p>
<p>imposes restrictions that are too draconian for most classes.</p>
<h3> <a name="Heading7">Eligibility For STL Containment</a></h3>
<p>In order to qualify as an element in an STL container, an object must possess 
  a copy constructor, an assignment operator, and a destructor as public members 
  (more on this in Chapter 10, "STL and Generic Programming"). </p>
<p>A default constructor is also required for certain STL container operations, 
  as you saw in the preceding example. </p>
<p>Many operating systems store the files in a directory as a linked list of file 
  objects. By omitting a default constructor from <tt>File</tt>, the implementer 
  severely compromises the capability of its users to implement a file system 
  as a <tt>std::list&lt;File&gt;</tt>.</p>
<p>For a class such as <tt>File</tt>, whose constructor must initialize its members 
  with user-supplied values, it might still be possible to define a default constructor. 
  Instead of supplying the necessary path and open mode as constructor arguments, 
  a default constructor can read them from a sequential database file.</p>
<h3> <a name="Heading8">When Are Default Constructors Undesirable?</a></h3>
<p>Still, a default constructor can be undesirable in some cases. One such case 
  is a singleton object. Because a singleton object must have one and only one 
  instance, it is recommended that you block the creation of built-in arrays and 
  containers of such objects by making the default constructor inaccessible. For 
  example</p>
<pre>
<tt>#include&lt;string&gt;</tt>
<tt>using namespace std;</tt>
<tt>int API_getHandle(); //system API function</tt>
<tt>class Application</tt>
<tt>{</tt>
<tt>private:</tt>
<tt>  string name;</tt>
<tt>  int handle;</tt>
<tt>  Application(); // make default constructor inaccessible</tt>
<tt>public:</tt>
<tt>  explicit Application(int handle);</tt>
<tt>  ~Application();</tt>
<tt>};</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt>  Application theApp( API_getHandle() ); //ok</tt>
<tt>  Application apps[10]; //error, default constructor is inaccessible</tt>
<tt>}</tt>
</pre>
<p>Class <tt>Application</tt> does not have a default constructor; therefore, 
  it is impossible to create arrays and containers of <tt>Application</tt> objects. 
  In this case, the lack of a default constructor is intentional (other implementation 
  details are still required to ensure that a single instance -- and only a single 
  instance -- of <tt>Application</tt> is created. However, making the default 
  constructor inaccessible is one of these details).</p>
<h3> <a name="Heading9"> Constructors Of Fundamental Types</a></h3>
<p>Fundamental types such as <tt>char</tt>, <tt>int</tt>, and <tt>float</tt> have 
  constructors, as do user-defined types. You can initialize a variable by explicitly 
  invoking its default constructor:</p>
<pre>
<tt>int main()</tt>
<tt>{</tt>
<tt>  char c = char();</tt>
<tt>  int n = int ();</tt>
<tt>  return 0;</tt>
<tt>}</tt>
</pre>
<p>The value that is returned by the explicit invocation of the default constructor 
  of a fundamental type is equivalent to casting 0 to that type. In other words,</p>
<pre>
<tt>char c = char();</tt>
</pre>
<p>is equivalent to</p>
<pre>
<tt>char c = char(0);</tt>
</pre>
<p>Of course, it is possible to initialize a fundamental type with values other 
  than 0:</p>
<pre>
<tt>float f = float (0.333);</tt>
<tt>char c = char ('a');</tt>
</pre>
<p>Normally, you use the shorter notation:</p>
<pre>
<tt>char c = 'a';</tt>
<tt>float f = 0.333;</tt>
</pre>
<p>However, this language extension enables uniform treatment in templates for 
  fundamental types and user-defined types. Fundamental types that are created 
  on the free store using the operator <tt>new</tt> can be initialized in a similar 
  manner:</p>
<pre>
<tt>int *pi= new int (10); 	</tt>
<tt>float *pf = new float (0.333);</tt>
</pre>
<h3> <a name="Heading10">explicit Constructors</a></h3>
<p>A constructor that takes a single argument is, by default, an implicit conversion 
  operator, which converts its argument to an object of its class (see also Chapter 
  3, "Operator Overloading"). Examine the following concrete example:</p>
<pre>
<tt>class string</tt>
<tt>{</tt>
<tt>private:</tt>
<tt>  int size;</tt>
<tt>  int capacity;</tt>
<tt>  char *buff;</tt>
<tt>public:</tt>
<tt>  string();</tt>
<tt>  string(int size);  // constructor and implicit conversion operator</tt>
<tt>  string(const char *); // constructor and implicit conversion operator</tt>
<tt>  ~string();</tt>
<tt>};</tt>
</pre>
<p>Class <tt>string</tt> has three constructors: a default constructor, a constructor 
  that takes <tt>int</tt>, and a constructor that constructs a string from <tt>const 
  char *</tt>. The second constructor is used to create an empty <tt>string</tt> 
  object with an initial preallocated buffer at the specified size. However, in 
  the case of class <tt>string</tt>, the automatic conversion is dubious. Converting 
  an <tt>int</tt> into a string object doesn't make sense, although this is exactly 
  what this constructor does. Consider the following:</p>
<pre>
<tt>int main()</tt>
<tt>{</tt>
<tt>  string s = "hello"; //OK, convert a C-string into a string object</tt>
<tt>  int ns = 0;</tt>
<tt>  s = 1; // 1 oops, programmer intended to write ns = 1,</tt>
<tt>}</tt>
</pre>
<p>In the expression <tt>s= 1;</tt>, the programmer simply mistyped the name of 
  the variable <tt>ns,</tt> typing <tt>s</tt> instead. Normally, the compiler 
  detects the incompatible types and issues an error message. However, before 
  ruling it out, the compiler first searches for a user-defined conversion that 
  allows this expression; indeed, it finds the constructor that takes <tt>int</tt>. 
  Consequently, the compiler interprets the expression <tt>s= 1;</tt> as if the 
  programmer had written</p>
<pre>
<tt>s = string(1);</tt>
</pre>
<p>You might encounter a similar problem when calling a function that takes a 
  <tt>string</tt> argument. The following example can either be a cryptic coding 
  style or simply a programmer's typographical error. However, due to the implicit 
  conversion constructor of class <tt>string</tt>, it will pass unnoticed:</p>
<pre>
<tt>int f(string s);</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt>  f(1); // without a an explicit constructor,</tt>
<tt>        //this call is expanded into:  f ( string(1) );</tt>
<tt>        //was that intentional or merely a programmer's typo?</tt>
<tt>}</tt>
</pre>
<p></p>
<p>'In order to avoid such implicit conversions, a constructor that takes one 
  argument needs to be declared <tt>explicit</tt>:</p>
<pre>
<tt>class string</tt>
<tt>{</tt>
<tt>//...</tt>
<tt>public:</tt>
<tt>  explicit string(int size);  // block implicit conversion</tt>
<tt>  string(const char *); //implicit conversion</tt>
<tt>  ~string();</tt>
<tt>};</tt>
</pre>
<p>An <tt>explicit</tt> constructor does not behave as an implicit conversion 
  operator, which enables the compiler to catch the typographical error this time:</p>
<pre>
<tt>int main()</tt>
<tt>{</tt>
<tt>  string s = "hello"; //OK, convert a C-string into a string object</tt>
<tt>  int ns = 0;</tt>
<tt>  s = 1; // compile time error ; this time the compiler catches the typo</tt>
<tt>}</tt>
</pre>
<p>Why aren't all constructors automatically declared <tt>explicit</tt>? Under 
  some conditions, the automatic type conversion is useful and well behaved. A 
  good example of this is the third constructor of <tt>string</tt>:</p>
<pre>
<tt>string(const char *);</tt>
</pre>
<p>The implicit type conversion of <tt>const char *</tt> to a string object enables 
  its users to write the following:</p>
<pre>
<tt>  string s;</tt>
<tt>  s = "Hello";</tt>
</pre>
<p>The compiler implicitly transforms this into</p>
<pre>
<tt>  string s;</tt>
<tt>  //pseudo C++ code:</tt>
<tt>  s = string ("Hello"); //create a temporary and assign it to s</tt>
</pre>
<p>On the other hand, if you declare this constructor <tt>explicit</tt>, you have 
  to use explicit type conversion:</p>
<pre>
<tt>class string</tt>
<tt>{</tt>
<tt>//...</tt>
<tt>public:</tt>
<tt>  explicit string(const char *);</tt>
<tt>};</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt>  string s;</tt>
<tt>  s = string("Hello");  //explicit conversion now required</tt>
<tt>  return 0;</tt>

⌨️ 快捷键说明

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