📄 chapter11.html
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<!--
This document was converted from RTF source:
By rtftohtml 4.19
See http://www.sunpack.com/RTF
Filename:TIC2Vone.rtf
Application Directory:C:\TOOLS\RTF2HTML\
Subject:
Author:Bruce Eckel
Operator:Bruce Eckel
Document Comments:
Version Comments:
Comments:
Keywords:
Translation Date:09/27/2001
Translation Time:05:25:44
Translation Platform:Win32
Number of Output files:22
This File:Chapter11.html
SplitDepth=1
SkipNavPanel=1
SkipLeadingToc=1
SkipTrailingToc=1
GenContents=1
GenFrames=1
GenIndex=1
-->
<HEAD lang="en"><META http-equiv="Content-Type" content="text/html">
<TITLE>11: References & the Copy-Constructor</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF"><DIV ALIGN="CENTER">
<a href="http://www.MindView.net">
<img src="mindview-head.gif" alt="MindView Inc." BORDER = "0"></a>
<CENTER>
<FONT FACE="Verdana" size = "-1">
[ <a href="README-HTML.txt">Viewing Hints</a> ]
[ <a href="http://www.mindview.net/CPPServices/SolutionGuide.html">Exercise Solutions</a> ]
[ <a href="http://www.mindview.net/ThinkingInCPP2e.html">Volume 2</a> ]
[ <a href="http://www.mindview.net/MailingList.html">Free Newsletter</a> ] <br>
[ <a href="http://www.mindview.net/CPPServices/#PublicSeminars">Seminars</a> ]
[ <a href="http://www.mindview.net/CPPServices/#SeminarsOnCD">Seminars on CD ROM</a> ]
[ <a href="http://www.mindview.net/CPPServices/#ConsultingServices">Consulting</a> ]
</FONT>
<H2><FONT FACE="Verdana">
Thinking in C++, 2nd ed. Volume 1</FONT></H2></FONT>
<H3><FONT FACE="Verdana">©2000 by Bruce Eckel</FONT></H3></FONT>
<FONT FACE="Verdana" size = "-1">
[ <a href="Chapter10.html">Previous Chapter</a> ]
[ <a href="Contents.html">Table of Contents</a> ]
[ <a href="DocIndex.html">Index</a> ]
[ <a href="Chapter12.html">Next Chapter</a> ]
</FONT>
</CENTER>
</P></DIV><A NAME="_Toc472654932"></A><A NAME="Heading324"></A><FONT FACE = "Verdana"><H1 ALIGN="LEFT">
11: References & the Copy-Constructor</H1></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Verdana" SIZE=4>References are like constant
pointers that are automatically dereferenced by the compiler. </FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Although references
<A NAME="Index1845"></A>also exist in Pascal, the C++ version was taken from the
Algol language. They are essential in C++ to support the syntax of operator
overloading <A NAME="Index1846"></A><A NAME="Index1847"></A>(see Chapter 12),
but they are also a general convenience to control the way arguments are passed
<A NAME="Index1848"></A>into and out of functions.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This chapter will first look briefly at
the differences between pointers <A NAME="Index1849"></A>in C and C++, then
introduce references. But the bulk of the chapter will delve into a rather
confusing issue for the new C++ programmer: the
copy-constructor<A NAME="Index1850"></A><A NAME="Index1851"></A>, a special
constructor (requiring references) that makes a new object from an existing
object of the same type. The copy-constructor is used by the compiler to pass
and return objects <I>by value</I>
<A NAME="Index1852"></A><A NAME="Index1853"></A>into and out of
functions.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Finally, the somewhat obscure C++
<I>pointer-to-member</I> feature is
illuminated.</FONT><A NAME="_Toc305593227"></A><A NAME="_Toc305628699"></A><A NAME="_Toc312373958"></A><A NAME="_Toc472654933"></A><BR></P></DIV>
<A NAME="Heading325"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Pointers in C++</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The most important difference between
pointers in C and those in C++ is that
<A NAME="Index1854"></A><A NAME="Index1855"></A><A NAME="Index1856"></A>C++ is a
more strongly typed language. This stands out where
<A NAME="Index1857"></A><B>void*<A NAME="Index1858"></A><A NAME="Index1859"></A></B>
is concerned. C doesn’t let you casually assign a pointer of one type to
another, but it <I>does</I> allow you to accomplish this through a <B>void*</B>.
Thus,</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>bird* b;
rock* r;
<font color=#0000ff>void</font>* v;
v = r;
b = v;</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Because this “feature” of C
allows you to quietly treat any type like any other type, it leaves a big
<A NAME="Index1860"></A>hole in the type system. C++ doesn’t allow this;
the compiler gives you an error message, and if you really want to treat one
type as another, you must make it explicit, both to the compiler and to the
reader, using a cast. (Chapter 3 introduced C++’s improved
“explicit” casting
syntax.)</FONT><A NAME="_Toc305593228"></A><A NAME="_Toc305628700"></A><A NAME="_Toc312373959"></A><A NAME="_Toc472654934"></A><BR></P></DIV>
<A NAME="Heading326"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
References in C++</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">A <I>reference</I>
<A NAME="Index1861"></A>(<B>&</B>) is like a constant pointer that is
automatically dereferenced. It is usually used for function argument lists
<A NAME="Index1862"></A><A NAME="Index1863"></A>and function return
values<A NAME="Index1864"></A><A NAME="Index1865"></A>. But you can also make a
<A NAME="Index1866"></A><A NAME="Index1867"></A>free-standing reference. For
example,</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C11:FreeStandingReferences.cpp</font>
#include <iostream>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#009900>// Ordinary free-standing reference:</font>
<font color=#0000ff>int</font> y;
<font color=#0000ff>int</font>& r = y;
<font color=#009900>// When a reference is created, it must </font>
<font color=#009900>// be initialized to a live object. </font>
<font color=#009900>// However, you can also say:</font>
<font color=#0000ff>const</font> <font color=#0000ff>int</font>& q = 12; <font color=#009900>// (1)</font>
<font color=#009900>// References are tied to someone else's storage:</font>
<font color=#0000ff>int</font> x = 0; <font color=#009900>// (2)</font>
<font color=#0000ff>int</font>& a = x; <font color=#009900>// (3)</font>
<font color=#0000ff>int</font> main() {
cout << <font color=#004488>"x = "</font> << x << <font color=#004488>", a = "</font> << a << endl;
a++;
cout << <font color=#004488>"x = "</font> << x << <font color=#004488>", a = "</font> << a << endl;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In line (1), the compiler allocates a
piece of storage, initializes it with the value 12, and ties the reference to
that piece of storage. The point is that any reference must be tied to someone
<I>else’s</I> piece of storage. When you access a reference, you’re
accessing that storage. Thus, if you write lines like (2) and (3), then
incrementing <B>a</B> is actually incrementing <B>x</B>, as is shown in
<B>main( )</B>. Again, the easiest way to think about a reference is as a
fancy pointer. One advantage of this “pointer” is that you never
have to wonder whether it’s been initialized (the compiler enforces it)
and how to dereference it (the compiler does it).</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">There are certain rules when using
references<A NAME="Index1868"></A><A NAME="Index1869"></A><A NAME="Index1870"></A>:</FONT><BR></P></DIV>
<OL>
<LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">A reference must be
initialized when it is created. (Pointers can be initialized at any
time.)</FONT><LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Once a
reference is initialized to an object, it cannot be changed to refer to another
object. (Pointers can be pointed to another object at any
time.)</FONT><LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">You cannot
have NULL references. You must always be able to assume that a reference is
connected to a legitimate piece of
storage.</FONT><A NAME="_Toc312373960"></A><A NAME="_Toc472654935"></A></OL><A NAME="Heading327"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
References in functions</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The most common place you’ll see
references is as function arguments and return values. When a reference is used
as a function <A NAME="Index1871"></A>argument, any modification to the
reference <I>inside</I> the function will cause changes to the argument
<I>outside</I> the function. Of course, you could do the same thing by passing a
pointer, but a reference has much cleaner syntax. (You can think of a reference
as nothing more than a syntax convenience, if you want.)</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If you return <A NAME="Index1872"></A>a
reference from a function, you must take the same care as if you return a
pointer from a function. Whatever the reference is connected to shouldn’t
go away when the function returns, otherwise you’ll be referring to
unknown memory.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here’s an example:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C11:Reference.cpp</font>
<font color=#009900>// Simple C++ references</font>
<font color=#0000ff>int</font>* f(<font color=#0000ff>int</font>* x) {
(*x)++;
<font color=#0000ff>return</font> x; <font color=#009900>// Safe, x is outside this scope</font>
}
<font color=#0000ff>int</font>& g(<font color=#0000ff>int</font>& x) {
x++; <font color=#009900>// Same effect as in f()</font>
<font color=#0000ff>return</font> x; <font color=#009900>// Safe, outside this scope</font>
}
<font color=#0000ff>int</font>& h() {
<font color=#0000ff>int</font> q;
<font color=#009900>//! return q; // Error</font>
<font color=#0000ff>static</font> <font color=#0000ff>int</font> x;
<font color=#0000ff>return</font> x; <font color=#009900>// Safe, x lives outside this scope</font>
}
<font color=#0000ff>int</font> main() {
<font color=#0000ff>int</font> a = 0;
f(&a); <font color=#009900>// Ugly (but explicit)</font>
g(a); <font color=#009900>// Clean (but hidden)</font>
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The call to <B>f( )</B>
doesn’t have the convenience and cleanliness of using references, but
it’s clear that an address is being passed. In the call to
<B>g( )</B>, an address is being passed (via a reference), but you
don’t see it.</FONT><BR></P></DIV>
<A NAME="Heading328"></A><FONT FACE = "Verdana"><H4 ALIGN="LEFT">
const references<BR><A NAME="Index1873"></A><A NAME="Index1874"></A></H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The reference argument in
<B>Reference.cpp</B> works only when the argument is a non-<B>const</B> object.
If it is a <B>const</B> object, the function <B>g( )</B> will not accept
the argument, which is actually a good thing, because the function <I>does</I>
modify the outside argument. If you know the function will respect the
<B>const</B>ness of an object, making the argument a
<A NAME="Index1875"></A><B>const</B> reference will allow the function to be
used in all situations. This means that, for built-in types, the function will
not modify the argument, and for user-defined types, the function will call only
<B>const</B> member functions, and won’t modify any <B>public</B> data
members.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The use of <B>const</B> references in
function arguments is especially important because your function may receive a
<A NAME="Index1876"></A>temporary
object<A NAME="Index1877"></A><A NAME="Index1878"></A>. This might have been
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -