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

📄 chapter12.html

📁 《C++编程思想》中文版。。。。。。。。。。。。。
💻 HTML
📖 第 1 页 / 共 5 页
字号:
  b1 = b2 = b3;
}

<font color=#0000ff>int</font> main() {
  out &lt;&lt; <font color=#004488>"member functions:"</font> &lt;&lt; endl;
  Byte b1(47), b2(9);
  k(b1, b2);
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can see that <B>operator=</B> is only
allowed to be a member function. This is explained later.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Notice that all of the assignment
operators have code to check for
self-assignment<A NAME="Index1996"></A><A NAME="Index1997"></A><A NAME="Index1998"></A>;
this is a general guideline. In some cases this is not necessary; for example,
with <B>operator+=</B> you often <I>want</I> to say <B>A+=A</B> and have it add
<B>A</B> to itself. The most important place to check for self-assignment is
<A NAME="Index1999"></A><B>operator=<A NAME="Index2000"></A></B> because with
complicated objects disastrous results may occur. (In some cases it&#8217;s OK,
but you should always keep it in mind when writing
<B>operator=</B>.)</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">All of the operators shown in the
previous two examples are overloaded to handle a single type. It&#8217;s also
possible to overload operators to handle mixed types, so you can add apples to
oranges, for example. Before you start on an exhaustive overloading of
operators, however, you should look at the section on automatic type conversion
later in this chapter. Often, a type conversion in the right place can save you
a lot of overloaded
operators.</FONT><A NAME="_Toc312373977"></A><A NAME="_Toc472654952"></A><BR></P></DIV>
<A NAME="Heading355"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Arguments &amp; return
values<BR><A NAME="Index2001"></A><A NAME="Index2002"></A><A NAME="Index2003"></A></H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">It may seem a little confusing at first
when you look at <B>OverloadingUnaryOperators.cpp</B>, <B>Integer.h</B> and
<B>Byte.h </B>and see all the different ways that arguments are passed and
returned. Although you <I>can</I> pass and return arguments any way you want to,
the choices in these examples were not selected at random. They follow a logical
pattern, the same one you&#8217;ll want to use in most of your
choices<A NAME="Index2004"></A><A NAME="Index2005"></A><A NAME="Index2006"></A><A NAME="Index2007"></A><A NAME="Index2008"></A><A NAME="Index2009"></A>.</FONT><BR></P></DIV>
<OL>
<LI><FONT FACE="Verdana">	</FONT><FONT FACE="Georgia">As with any function
argument, if you only need to read from the argument and not change it, default
to passing it as a <B>const</B> reference. Ordinary arithmetic operations (like
<B>+ </B>and <B>&#8211;</B>, etc.) and Booleans will not change their arguments,
so pass by <B>const </B>reference is predominantly what you&#8217;ll use. When
the function is a class member, this translates to making it a <B>const</B>
member function. Only with the operator-assignments (like <B>+=</B>) and the
<B>operator=</B>, which change the left-hand argument, is the left argument
<I>not</I> a constant, but it&#8217;s still passed in as an address because it
will be changed.</FONT><LI><FONT FACE="Verdana">	</FONT><FONT FACE="Georgia">The
type of return value you should select depends on the expected meaning of the
operator. (Again, you can do anything you want with the arguments and return
values.) If the effect of the operator is to produce a new value, you will need
to generate a new object as the return value. For example,
<B>Integer::operator+</B> must produce an <B>Integer</B> object that is the sum
of the operands. This object is returned by value as a <B>const</B>, so the
result cannot be modified as an
lvalue.</FONT><LI><FONT FACE="Verdana">	</FONT><FONT FACE="Georgia">All the
assignment operators modify the lvalue. To allow the result of the assignment to
be used in chained expressions, like <B>a=b=c</B>, it&#8217;s expected that you
will return a reference to that same lvalue that was just modified. But should
this reference be a <B>const</B> or non<B>const</B>? Although you read
<B>a=b=c</B> from left to right, the compiler parses it from right to left, so
you&#8217;re not forced to return a non<B>const</B> to support assignment
chaining. However, people do sometimes expect to be able to perform an operation
on the thing that was just assigned to, such as <B>(a=b).func(&#160;);</B> to
call <B>func(&#160;)</B> on <B>a</B> after assigning <B>b</B> to it. Thus, the
return value for all of the assignment operators should be a non<B>const</B>
reference to the
lvalue.</FONT><LI><FONT FACE="Verdana">	</FONT><FONT FACE="Georgia">For the
logical operators, everyone expects to get at worst an <B>int</B> back, and at
best a <B>bool</B>. (Libraries developed before most compilers supported
C++&#8217;s built-in <B>bool</B> will use <B>int</B> or an equivalent
<B>typedef</B>.)</FONT></OL><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The increment
and decrement operators
<A NAME="Index2010"></A><A NAME="Index2011"></A><A NAME="Index2012"></A>present
a dilemma because of the pre- and postfix versions. Both versions change the
object and so cannot treat the object as a <B>const</B>. The prefix version
returns the value of the object after it was changed, so you expect to get back
the object that was changed. Thus, with prefix you can just return <B>*this</B>
as a reference. The postfix version is supposed to return the value
<I>before</I> the value is changed, so you&#8217;re forced to create a separate
object to represent that value and return it. So with postfix you must return by
value if you want to preserve the expected meaning. (Note that you&#8217;ll
sometimes find the increment and decrement operators returning an <B>int</B> or
<B>bool</B> to indicate, for example, whether an object designed to move through
a list is at the end of that list.) Now the question is: Should these be
returned as <B>const</B> or non<B>const</B>? If you allow the object to be
modified and someone writes <B>(++a).func(&#160;)</B>, <B>func(&#160;)</B> will
be operating on <B>a</B> itself, but with <B>(a++).func(&#160;)</B>,
<B>func(&#160;)</B> operates on the temporary object returned by the postfix
<B>operator++</B>. Temporary objects are automatically <B>const</B>, so this
would be flagged by the compiler, but for consistency&#8217;s sake it may make
more sense to make them both <B>const</B>, as was done here. Or you may choose
to make the prefix version non-<B>const </B>and the postfix <B>const</B>.<B>
</B>Because of the variety of meanings you may want to give the increment and
decrement operators, they will need to be considered on a case-by-case
basis.</FONT><BR></P></DIV>
<A NAME="Heading356"></A><FONT FACE = "Verdana"><H4 ALIGN="LEFT">
Return by value as
const<BR><A NAME="Index2013"></A><A NAME="Index2014"></A></H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Returning by value as a <B>const</B> can
seem a bit subtle at first, so it deserves a bit more explanation. Consider the
binary <B>operator+</B>. If you use it in an expression such as <B>f(a+b)</B>,
the result of <B>a+b</B> becomes a temporary object that is used in the call to
<B>f(&#160;)</B>. Because it&#8217;s a temporary, it&#8217;s automatically
<B>const</B>, so whether you explicitly make the return value <B>const</B> or
not has no effect.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">However, it&#8217;s also possible for you
to send a message to the return value of <B>a+b</B>, rather than just passing it
to a function. For example, you can say <B>(a+b).g(&#160;)</B>, in which
<B>g(&#160;)</B> is some member function of <B>Integer</B>, in this case. By
making the return value <B>const</B>, you state that only a <B>const</B> member
function can be called for that return value. This is <B>const</B>-correct,
because it prevents you from storing potentially valuable information in an
object that will most likely be lost.</FONT><BR></P></DIV>
<A NAME="Heading357"></A><FONT FACE = "Verdana"><H4 ALIGN="LEFT">
The return
optimization<BR><A NAME="Index2015"></A><A NAME="Index2016"></A><A NAME="Index2017"></A><A NAME="Index2018"></A></H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">When new objects are created to return by
value, notice the form used. In <B>operator+</B>, for example:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>return</font> Integer(left.i + right.i);</PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This may look at first like a
&#8220;function call to a constructor,&#8221; but it&#8217;s not. The syntax is
that of a temporary object; the statement says &#8220;make a temporary
<B>Integer</B> object and return it.&#8221; Because of this, you might think
that the result is the same as creating a named local object and returning that.
However, it&#8217;s quite different. If you were to say
instead:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>Integer tmp(left.i + right.i);
<font color=#0000ff>return</font> tmp;</PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">three things will happen. First, the
<B>tmp</B> object is created including its constructor call. Second, the
copy-constructor<A NAME="Index2019"></A> copies the <B>tmp</B> to the location
of the outside return value. Third, the destructor is called for <B>tmp</B> at
the end of the scope.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In contrast, the &#8220;returning a
<A NAME="Index2020"></A>temporary&#8221; approach works quite differently. When
the compiler sees you do this, it knows that you have no other need for the
object it&#8217;s creating than to return it. The compiler takes advantage of
this by building the object <I>directly</I> into the location of the outside
return value. This requires only a single ordinary constructor call (no
copy-constructor is necessary) and there&#8217;s no destructor call because you
never actually create a local object. Thus, while it doesn&#8217;t cost anything
but programmer awareness, it&#8217;s significantly more efficient. This is often
called the <I>return value
optimization</I>.</FONT><A NAME="_Toc312373978"></A><A NAME="_Toc472654953"></A><BR></P></DIV>
<A NAME="Heading358"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Unusual operators<BR><A NAME="Index2021"></A><A NAME="Index2022"></A></H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Several additional operators have a
slightly different syntax for overloading.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The subscript, <B>operator[
]<A NAME="Index2023"></A></B>, must be a member function and it requires a
single argument. Because <B>operator[ ] </B>implies that the object it&#8217;s
being called for acts like an array, you will often return a reference from this
operator, so it can be conveniently used on the left-hand side of an equal sign.
This operator is commonly overloaded; you&#8217;ll see examples in the rest of
the book.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The operators <B>new</B> and
<B>delete</B> control dynamic storage allocation and can be overloaded in a
number of different ways. This topic is covered in the Chapter
13.</FONT><BR></P></DIV>
<A NAME="Heading359"></A><FONT FACE = "Verdana"><H4 ALIGN="LEFT">
Operator comma</H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The comma
operator<A NAME="Index2024"></A><A NAME="Index2025"></A> is called when it
appears next to an object of the type the comma is defined for. However,
&#8220;<B>operator,</B>&#8221;<B> </B>is <I>not </I>called for function argument
lists, only for objects that are out in the open, separated by commas. There
doesn&#8217;t seem to be a lot of practical uses for this operator; it&#8217;s
in the language for consistency. Here&#8217;s an example showing how the comma
function can be called when the comma appears <I>before</I> an object, as well
as after:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C12:OverloadingOperatorComma.cpp</font>
#include &lt;iostream&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

<font color=#0000ff>class</font> After {
<font color=#0000ff>public</font>:
  <font color=#0000ff>const</font> After&amp; <font color=#0000ff>operator</font>,(<font color=#0000ff>const</font> After&amp;) <font color=#0000ff>const</font> {
    cout &lt;&lt; <font color=#004488>"After::operator,()"</font> &lt;&lt; endl;
    <font color=#0000ff>return</font> *<font color=#0000ff>this</font>;
  }
};

<font color=#0000ff>class</font> Before {};

Before&amp; <font color=#0000ff>operator</font>,(<font color=#0000ff>int</font>, Before&amp; b) {
  cout &lt;&lt; <font color=#004488>"Before::operator,()"</font> &lt;&lt; endl;
  <font color=#0000ff>return</font> b;
}

<font color=#0000ff>int</font> main() {
  After a, b;
  a, b;  <font color=#009900>// Operator comma called</font>

  Before c;
  1, c;  <font color=#009900>// Operator comma called</font>
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The global function allows the comma to
be placed before the object in question. The usage shown is fairly obscure and
questionable. Although you would probably use a comma-separated list as part of
a more complex expression, it&#8217;s too subtle to use in most
situations.</FONT><BR></P></DIV>
<A NAME="Heading360"></A><FONT FACE = "Verdana"><H4 ALIGN="LEFT">
Operator-&gt;<BR><A NAME="Index2026"></A><A NAME="Index2027"></A></H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The
<B>operator&#8211;&gt;<A NAME="Index2028"></A><A NAME="Index2029"></A><A NAME="Index2030"></A></B>
is generally used when you want to make an object appear to be a pointer. Since
such an object has more &#8220;smarts&#8221; built into it than exist for a
typical pointer, an object like this is often called a <I>smart pointer</I>.
These are especially useful if you want to &#8220;wrap&#8221; a class around a
pointer to make that pointer safe, or in the common usage of an
<I>iterator<A NAME="Index2031"></A></I>, which is an object that moves through a
<I>collection</I> <A NAME="Index2032"></A>/<I>container
<A NAME="Index2033"></A></I>of other objects and selects them one at a time,
without providin

⌨️ 快捷键说明

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