📄 index.html
字号:
<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& 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 <vector></tt>
<tt>using namespace std;</tt>
<tt>void f()</tt>
<tt>{</tt>
<tt> vector <File> fv(10); //error, File has no default constructor</tt>
<tt> vector <File> 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<File></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<string></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 + -