📄 chapter08.html
字号:
<font color=#0000ff>int</font> <font color=#0000ff>const</font>* v;
<font color=#0000ff>int</font> d = 1;
<font color=#0000ff>int</font>* <font color=#0000ff>const</font> w = &d;
<font color=#0000ff>const</font> <font color=#0000ff>int</font>* <font color=#0000ff>const</font> x = &d; <font color=#009900>// (1)</font>
<font color=#0000ff>int</font> <font color=#0000ff>const</font>* <font color=#0000ff>const</font> x2 = &d; <font color=#009900>// (2)</font>
<font color=#0000ff>int</font> main() {} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<A NAME="Heading256"></A><FONT FACE = "Verdana"><H4 ALIGN="LEFT">
Formatting<BR><A NAME="Index1499"></A><A NAME="Index1500"></A><A NAME="Index1501"></A></H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This book makes a point of only putting
one pointer definition on a line, and initializing each pointer at the point of
definition whenever possible. Because of this, the formatting style of
“attaching” the ‘<B>*</B>’ to the data type is
possible:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>int</font>* u = &i;</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia"><I>as if</I> <B>int*</B> were a discrete
type unto itself. This makes the code easier to understand, but unfortunately
that’s not actually the way things work. The ‘<B>*</B>’ in
fact binds to the identifier, not the type. It can be placed anywhere between
the type name and the identifier. So you could do this:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>int</font> *u = &i, v = 0;</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">which creates an <B>int* u</B>, as
before, and a non-pointer <B>int v</B>. Because readers often find this
confusing, it is best to follow the form shown in this
book.</FONT><A NAME="_Toc312373911"></A><A NAME="_Toc472654885"></A><BR></P></DIV>
<A NAME="Heading257"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Assignment and type checking</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">C++ is very particular about type
checking, and this extends to
<A NAME="Index1502"></A><A NAME="Index1503"></A>pointer assignments. You can
assign the address of a non-<B>const</B> object to a <B>const</B> pointer
because you’re simply promising not to change something that is OK to
change. However, you can’t assign the address of a <B>const</B> object to
a non-<B>const</B> pointer because then you’re saying you might change the
object via the pointer. Of course, you can always use a
<A NAME="Index1504"></A>cast to force such an assignment, but this is bad
programming practice because you are then breaking the <B>const</B>ness of the
object, along with any safety promised by the <B>const</B>. For
example:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C08:PointerAssignment.cpp</font>
<font color=#0000ff>int</font> d = 1;
<font color=#0000ff>const</font> <font color=#0000ff>int</font> e = 2;
<font color=#0000ff>int</font>* u = &d; <font color=#009900>// OK -- d not const</font>
<font color=#009900>//! int* v = &e; // Illegal -- e const</font>
<font color=#0000ff>int</font>* w = (<font color=#0000ff>int</font>*)&e; <font color=#009900>// Legal but bad practice</font>
<font color=#0000ff>int</font> main() {} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Although C++ helps prevent errors it does
not protect you from yourself if you want to break the safety
mechanisms.</FONT><BR></P></DIV>
<A NAME="Heading258"></A><FONT FACE = "Verdana"><H4 ALIGN="LEFT">
Character array literals</H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The place where strict <B>const</B>ness
is not enforced is with character array
literals<A NAME="Index1505"></A><A NAME="Index1506"></A>. You can
say</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>char</font>* cp = <font color=#004488>"howdy"</font>;</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">and the compiler will accept it without
complaint. This is technically an error because a character array literal
(<B>“howdy”</B> in this case) is created by the compiler as a
constant character array, and the result of the quoted character array is its
starting address in memory. Modifying any of the characters in the array is a
runtime error, although not all compilers enforce this
correctly.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">So character array literals are actually
constant character arrays. Of course, the compiler lets you get away with
treating them as non-<B>const</B> because there’s so much existing C code
that relies on this. However, if you try to change the values in a character
array literal, the behavior is undefined, although it will probably work on many
machines.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If you want to be able to modify the
string, put it in an array:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>char</font> cp[] = <font color=#004488>"howdy"</font>;</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Since compilers often don’t enforce
the difference you won’t be reminded to use this latter form and so the
point becomes rather
subtle.</FONT><A NAME="_Toc305628677"></A><A NAME="_Toc312373912"></A><A NAME="_Toc472654886"></A><BR></P></DIV>
<A NAME="Heading259"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Function arguments <BR>& return values</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The use of <B>const</B> to specify
function arguments <A NAME="Index1507"></A><A NAME="Index1508"></A>and return
values<A NAME="Index1509"></A> is another place where the concept of constants
can be confusing. If you are passing objects <I>by
value<A NAME="Index1510"></A></I>, specifying <B>const</B> has no meaning to the
client (it means that the passed argument cannot be modified inside the
function). If you are returning an object of a user-defined type by value as a
<B>const</B>, it means the returned value cannot be modified. If you are passing
and returning <I>addresses<A NAME="Index1511"></A></I>, <B>const</B> is a
promise that the destination of the address will not be
changed.</FONT><A NAME="_Toc312373913"></A><A NAME="_Toc472654887"></A><BR></P></DIV>
<A NAME="Heading260"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Passing by const value</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can specify that function arguments
are <B>const</B> when passing them by value, such as</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>void</font> f1(<font color=#0000ff>const</font> <font color=#0000ff>int</font> i) {
i++; <font color=#009900>// Illegal -- compile-time error</font>
} </PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">but what does this mean? You’re
making a promise that the original value of the variable will not be changed by
the function <B>f1( )</B>. However, because the argument is passed by
value, you immediately make a copy of the original variable, so the promise to
the client is implicitly kept.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Inside the function, the <B>const</B>
takes on meaning: the argument cannot be changed. So it’s really a tool
for the creator of the function, and not the caller.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">To avoid confusion to the caller, you can
make the argument a <A NAME="Index1512"></A><B>const</B> <I>inside</I> the
function, rather than in the argument list. You could do this with a pointer,
but a nicer syntax is achieved with the
<A NAME="Index1513"></A><I>reference</I>, a subject that will be fully developed
in Chapter 11. Briefly, a reference is like a constant pointer that is
automatically dereferenced, so it has the effect of being an alias to an object.
To create a reference, you use the <B>&</B> in the definition. So the
non-confusing function definition looks like this:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>void</font> f2(<font color=#0000ff>int</font> ic) {
<font color=#0000ff>const</font> <font color=#0000ff>int</font>& i = ic;
i++; <font color=#009900>// Illegal -- compile-time error</font>
} </PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Again, you’ll get an error message,
but this time the <B>const</B>ness of the local object is not part of the
function signature; it only has meaning to the implementation of the function
and therefore it’s hidden from the
client.</FONT><A NAME="_Toc312373914"></A><A NAME="_Toc472654888"></A><BR></P></DIV>
<A NAME="Heading261"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Returning by const
value<BR><A NAME="Index1514"></A><A NAME="Index1515"></A></H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">A similar truth holds for the return
value. If you say that a function’s return value is
<B>const</B>:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>const</font> <font color=#0000ff>int</font> g();</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">you are promising that the original
variable (inside the function frame) will not be modified. And again, because
you’re returning it by value, it’s copied so the original value
could never be modified via the return value.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">At first, this can make the specification
of <B>const</B> seem meaningless. You can see the apparent lack of effect of
returning <B>const</B>s by value in this example: </FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C08:Constval.cpp</font>
<font color=#009900>// Returning consts by value</font>
<font color=#009900>// has no meaning for built-in types</font>
<font color=#0000ff>int</font> f3() { <font color=#0000ff>return</font> 1; }
<font color=#0000ff>const</font> <font color=#0000ff>int</font> f4() { <font color=#0000ff>return</font> 1; }
<font color=#0000ff>int</font> main() {
<font color=#0000ff>const</font> <font color=#0000ff>int</font> j = f3(); <font color=#009900>// Works fine</font>
<font color=#0000ff>int</font> k = f4(); <font color=#009900>// But this works fine too!</font>
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">For built-in types, it doesn’t
matter whether you return by value as a <B>const</B>, so you should avoid
confusing the client programmer and leave off the <B>const</B> when returning a
built-in type by value.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Returning by value as a <B>const</B>
becomes important when you’re dealing with user-defined types. If a
function returns a class object by value as a <B>const</B>, the return value of
that function cannot be an lvalue <A NAME="Index1516"></A>(that is, it cannot be
assigned to or otherwise modified). For example:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C08:ConstReturnValues.cpp</font>
<font color=#009900>// Constant return by value</font>
<font color=#009900>// Result cannot be used as an lvalue</font>
<font color=#0000ff>class</font> X {
<font color=#0000ff>int</font> i;
<font color=#0000ff>public</font>:
X(<font color=#0000ff>int</font> ii = 0);
<font color=#0000ff>void</font> modify();
};
X::X(<font color=#0000ff>int</font> ii) { i = ii; }
<font color=#0000ff>void</font> X::modify() { i++; }
X f5() {
<font color=#0000ff>return</font> X();
}
<font color=#0000ff>const</font> X f6() {
<font color=#0000ff>return</font> X();
}
<font color=#0000ff>void</font> f7(X& x) { <font color=#009900>// Pass by non-const reference</font>
x.modify();
}
<font color=#0000ff>int</font> main() {
f5() = X(1); <font color=#009900>// OK -- non-const return value</font>
f5().modify(); <font color=#009900>// OK</font>
<font color=#009900>//! f7(f5()); // Causes warning or error</font>
<font color=#009900>// Causes compile-time errors:</font>
<font color=#009900>//! f7(f5());</font>
<font color=#009900>//! f6() = X(1);</font>
<font color=#009900>//! f6().modify();</font>
<font color=#009900>//! f7(f6());</font>
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -