📄 e.htm
字号:
The next two terms we need to grapple with are <I>initialization</I> and <I>assignment</I>. An object's initialization occurs when it is given a value for the very first time. For objects of classes or structs with constructors, initialization is <I>always</I> accomplished by calling a constructor. This is quite different from object assignment, which occurs when an object that is already initialized is given a new <NOBR>value:<SCRIPT>create_link(64);</SCRIPT>
</NOBR></P>
<UL><A NAME="1760"></A>
<PRE>string s1; // initialization
string s2("Hello"); // initialization
string s3 = s2; // initialization
</PRE><A NAME="1761"></A>
<PRE>s1 = s3; // assignment
</PRE>
</UL>
<A NAME="1762"></A>
<P><A NAME="dingp65"></A>
From a purely operational point of view, the difference between initialization and assignment is that the former is performed by a constructor while the latter is performed by <CODE>operator=</CODE>. In other words, the two processes correspond to different function <NOBR>calls.<SCRIPT>create_link(65);</SCRIPT>
</NOBR></P>
<P><A NAME="dingp66"></A><A NAME="1763"></A>
The reason for the distinction is that the two kinds of functions must worry about different things. Constructors usually have to check their arguments for validity, whereas most assignment operators can take it for granted that their argument is legitimate (because it has already been constructed). On the other hand, the target of an assignment, unlike an object undergoing construction, may already have resources allocated to it. These resources typically must be released before the new resources can be assigned. Frequently, one of these resources is memory. Before an assignment operator can allocate memory for a new value, it must first deallocate the memory that was allocated for the old <NOBR>value.<SCRIPT>create_link(66);</SCRIPT>
</NOBR></P>
<P><A NAME="dingp67"></A><A NAME="1764"></A>
Here is how a <CODE>String</CODE> constructor and assignment operator could be <NOBR>implemented:<SCRIPT>create_link(67);</SCRIPT>
</NOBR></P>
<UL><A NAME="20806"></A>
<PRE>// a possible String constructor
String::String(const char *value)
{
if (value) { // if value ptr isn't null
data = new char[strlen(value) + 1];
strcpy(data,value);
}
else { // handle null value ptr<A NAME="1"></A><A HREF="#2"onMouseOver = "self.status = 'Footnote 3'; return true" onMouseOut = "self.status = self.defaultStatus"><sup>3</sup></A>
<!--<A HREF="#20816"><sup>1</sup></A>-->
data = new char[1];
<A NAME="p9"></A> *data = '\0'; // add trailing
null char
}
}
</PRE><A NAME="1766"></A>
<PRE>// a possible String assignment operator
String& String::operator=(const String& rhs)
{
if (this == &rhs)
return *this; // see <A HREF="#2264"onMouseOver = "self.status = 'Item 17'; return true" onMouseOut = "self.status = self.defaultStatus">Item 17</A>
delete [] data; // delete old memory
data = // allocate new memory
new char[strlen(rhs.data) + 1];
strcpy(data, rhs.data);
return *this; // see <A HREF="#2182"onMouseOver = "self.status = 'Item 15'; return true" onMouseOut = "self.status = self.defaultStatus">Item 15</A>
}
</PRE>
</UL>
<A NAME="1767"></A>
<P><A NAME="dingp68"></A>
Notice how the constructor must check its parameter for validity and how it must take pains to ensure that the member <CODE>data</CODE> is properly initialized, i.e., points to a <CODE>char*</CODE> that is properly null-terminated. On the other hand, the assignment operator takes it for granted that its parameter is legitimate. Instead, it concentrates on detecting pathological conditions, such as assignment to itself (see <A HREF="#2264"onMouseOver = "self.status = 'Item 17'; return true" onMouseOut = "self.status = self.defaultStatus">Item 17</A>), and on deallocating old memory before allocating new memory. The differences between these two functions typify the differences between object initialization and object assignment. By the way, if the "<CODE>[]</CODE>" notation in the use of <CODE>delete</CODE> is new to you (pardon the pun), Items <A HREF="#1869"onMouseOver = "self.status = '5'; return true" onMouseOut = "self.status = self.defaultStatus">5</A> and <A HREF="../MEC/M_FR.HTM#33985" TARGET="_top" onMouseOver = "self.status = 'M8'; return true" onMouseOut = "self.status = self.defaultStatus">M8</A> should dispel any confusion you may <NOBR>have.<SCRIPT>create_link(68);</SCRIPT>
</NOBR></P>
<P><A NAME="dingp69"></A><A NAME="1768"></A>A final term that warrants discussion is <I>client</I>. A client is a programmer, one who uses the code you write. When I talk about clients in this book, I am referring to people looking at your code, trying to figure out what it does; to people reading your class definitions, attempting to determine whether they want to inherit from your classes; to people examining your design decisions, hoping to glean insights into their <NOBR>rationale.<SCRIPT>create_link(69);</SCRIPT>
</NOBR></P>
<P><A NAME="dingp70"></A><A NAME="1769"></A>
You may not be used to thinking about your clients, but I'll spend a good deal of time trying to convince you to make their lives as easy as you can. After all, you are a client of the software other people develop. Wouldn't you want those people to make things easy for you? Besides, someday you may find yourself in the uncomfortable position of having to use your <i>own</i> code, in which case your client will be <NOBR>you!<SCRIPT>create_link(70);</SCRIPT>
</NOBR></P>
<P><A NAME="dingp71"></A><A NAME="13076"></A>
I use two constructs in this book that may not be familiar to you. Both are relatively recent additions to C++. The first is the <CODE>bool</CODE> type, which has as its values the keywords <CODE>true</CODE> and <CODE>false</CODE>. This is the type now <A NAME="p10"></A>returned by the built-in relational operators (e.g., <CODE><</CODE>, <CODE>></CODE>, <CODE>==</CODE>, etc.) and tested in the condition part of <CODE>if</CODE>, <CODE>for</CODE>, <CODE>while</CODE>, and <CODE>do</CODE> statements. If your compilers haven't implemented <CODE>bool</CODE>, an easy way to approximate it is to use a typedef for <CODE>bool</CODE> and constant objects for <CODE>true</CODE> and <CODE>false</CODE>:<SCRIPT>create_link(71);</SCRIPT>
</P>
<UL><A NAME="13058"></A>
<PRE>typedef int bool;
</PRE><A NAME="13059"></A>
<PRE>const bool false = 0;
const bool true = 1;
</PRE>
</UL>
<P><A NAME="dingp72"></A><A NAME="13060"></A>
This is compatible with the traditional semantics of C and C++. The behavior
of programs using this approximation won't change when they're ported to
<CODE>bool</CODE>-supporting compilers. For a different way of approximating
<CODE>bool</CODE> — including a discussion of the advantages and
disadvantages of each approach — turn to the <A
HREF="../MEC/M_FR.HTM#71736" TARGET="_top" onMouseOver = "self.status =
'Introduction of More Effective C++'; return true" onMouseOut = "self.status
= self.defaultStatus">Introduction of <i>More Effective C++</i></A>.<SCRIPT>create_link(72);</SCRIPT>
</P>
<P><A NAME="dingp73"></A><A NAME="13062"></A>
The second new construct is really four constructs, the casting forms <CODE>static_cast</CODE>, <CODE>const_cast</CODE>, <CODE>dynamic_cast</CODE>, and <CODE>reinterpret_cast</CODE>. Conventional C-style casts look like <NOBR>this:<SCRIPT>create_link(73);</SCRIPT>
</NOBR></P>
<UL><A NAME="13120"></A>
<PRE>(<i>type</i>) <i>expression</i> // cast <i>expression</i> to be of
// type <i>type</i>
</PRE>
</UL><A NAME="13119"></A>
<A NAME="dingp74"></A><P><A NAME="dingp74"></A>
The new casts look like this:<SCRIPT>create_link(74);</SCRIPT>
<UL><A NAME="13123"></A>
<PRE>static_cast<type>(<i>expression</i>) // cast <i>expression</i> to be of
// type <i>type</i>
const_cast<type>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -