📄 index.html
字号:
</pre>
<p>When a true <tt>const</tt> variable is explicitly cast to a non-<tt>const</tt>
variable, the result of an attempt to change its value is undefined. This
is because an implementation can store true <tt>const</tt> data in the read-only
memory, and an attempt to write to it usually triggers a hardware exception.
(Using an explicit cast to remove <tt>const</tt>ness does not change the
physical memory properties of a variable.) For example</p>
<pre>
<tt>const int cnum = 0; //true const, may be stored in the machine's ROM</tt>
<tt>const int * pci = &cnum;</tt>
<tt>int *pi = const_cast<int*> (pci); // brute force attempt to unconst a variable</tt>
<tt>cout<< *pi; //OK, value of cnum is not modified</tt>
<tt>*pi = 2; //undefined, an attempt to modify cnum which is a true const variable</tt>
</pre>
<p>On the other hand, casting away the contractual <tt>const</tt>ness of an
object makes it possible to modify its value safely:</p>
<pre>
<tt> int num = 0;</tt>
<tt> const int * pci = &num; // *pci is a contractual const int</tt>
<tt> int *pi = const_cast<int*> (pci); // get rid of contractual const</tt>
<tt> *pi = 2; // OK, modify num's value</tt>
</pre>
<p>To conclude, <tt>const_cast</tt> is used to remove the <tt>const</tt> or
<tt>volatile</tt> qualities of an object. The resultant value can be used
in a context that requires a non-<tt>const</tt> or <tt>volatile</tt> object.
The cast operation is safe as long as the resultant value is not modified.
It is possible to modify the value of the resultant object only if the original
operand is not truly <tt>const</tt>.</p>
<h4> reinterpret_cast</h4>
<p><tt>reinterpret_cast <</tt><cite>to</cite><tt>> (</tt><cite>from</cite><tt>)</tt>
is used in low-level, unsafe conversions. <tt>reinterpret_cast</tt> merely
returns a low-level reinterpretation of the bit pattern of its operand.
Note, however, that <tt>reinterpret_cast</tt> cannot alter the cv-qualification
of its operand. The use of <tt>reinterpret_cast</tt> is dangerous and highly
non-portable -- use it sparingly. Following are examples of <tt>reinterpret_cast</tt>
uses. </p>
<p><tt>reinterpret_cast</tt> can be used to convert two pointers of completely
nonrelated types, as in</p>
<pre>
<tt>#include <cstdio></tt>
<tt>void mem_probe()</tt>
<tt>{</tt>
<tt> long n = 1000000L; long *pl = &n;</tt>
<tt> unsigned char * pc = reinterpret_cast <unsigned char *> (pl);</tt>
<tt> printf("%d %d %d %d", pc[0], pc[1], pc[2], pc[3]); //memory dump</tt>
<tt>}</tt>
</pre>
<p><tt>reinterpret_cast</tt> can cast integers to pointers, and vice versa.
For example</p>
<pre>
<tt>void *pv = reinterpret_cast<void *> (0x00fffd);</tt>
<tt> int ptr = reinterpret_cast<int> (pv);</tt>
</pre>
<p><tt>reinterpret_cast</tt> can also be used for conversions between different
types of function pointers. The result of using the resultant pointer to
call a function with a nonmatching type is undefined.</p>
<p>Do not use <tt>reinterpret_cast</tt> instead of <tt>static_cast</tt> --
the results might be undefined. For example, using <tt>reinterpret_cast</tt>
to navigate through the class hierarchy of a multiply-inherited object is
likely to yield the wrong result. Consider the following:</p>
<pre>
<tt>class A</tt>
<tt>{</tt>
<tt>private:</tt>
<tt> int n;</tt>
<tt>};</tt>
<tt>class B</tt>
<tt>{</tt>
<tt>private:</tt>
<tt> char c;</tt>
<tt>};</tt>
<tt>class C: public A, public B</tt>
<tt>{};</tt>
<tt>void func(B * pb)</tt>
<tt>{</tt>
<tt> C *pc1 = static_cast<C*> (pb); //correct offset adjustment</tt>
<tt> C *pc2 = reinterpret_cast<C*> (pb); //no offset calculated</tt>
<tt>}</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt> B b;</tt>
<tt> func(&b);</tt>
<tt>}</tt>
</pre>
<p>On my machine, <tt>pc1</tt> is assigned the value <tt>0x0064fdf0</tt>,
whereas <tt>pc2</tt> is assigned <tt>0x0064fdf4</tt>. This demonstrates
the difference between the two cast operators. Using the information that
is available at compile time, <tt>static_cast</tt> converts a pointer to
<tt>B</tt> to a pointer to <tt>C</tt>. It does so by causing <tt>pc1</tt>
to point at the start of <tt>C</tt> by subtracting the offset of the subobject
<tt>B</tt>. On the other hand, <tt>reinterpret_cast</tt> simply assigns
the binary value of <tt>pb</tt> to <tt>pc2</tt>, without any further adjustments;
for this reason, it yields the wrong result.</p>
<h4> dynamic_cast</h4>
<p>In pre-standard C++, as was noted earlier, C-style cast was used to perform
a dynamic cast as well. The cast was either static or dynamic, depending
on the type of the operand. The Standardization committee, however, opposed
this approach. An expensive runtime operation that looked exactly like a
static cast (that is, penalty-free) can mislead the users. For this purpose,
a new operator was introduced to the language: <tt>dynamic_cast</tt> (<tt>dynamic_cast</tt>
is discussed in further detail in Chapter 7, "Runtime Type Identification").
The name and the syntax of <tt>dynamic_cast</tt> were chosen to look markedly
different from C-style cast. All other new typecast operators follow this
model. Following is an example of <tt>dynamic_cast</tt>:</p>
<pre>
<tt>Derived *p = dynamic_cast<derived *> (&base); //pointer form</tt>
<tt>Derived & rd = dynamic_cast<derived &> (base); //reference form</tt>
</pre>
<h4> Conclusions</h4>
<p>The new typecasting operators are clearer and more explicit in their intended
purpose. A name such as <tt>dynamic_cast</tt><i>,</i> for example<i>,</i>
warns its users about its incurred runtime overhead. Most importantly, though,
the new cast operators are safer because they give the compiler a chance
to detect the programmer's mistakes.</p>
<p>Users might find the proliferation of cast operators somewhat confusing.
In particular, the choice between <tt>static_cast</tt> and <tt>reinterpret_cast</tt>
might not seem immediately clear. How to choose? As a rule, <tt>static_cast</tt>
is the first choice. If the compiler refuses to accept it, use <tt>reinterpret_cast</tt>
instead.</p>
<h3> <a name="Heading16">Built-in bool Type</a></h3>
<p>The built-in <tt>bool</tt> data type was added to the Standard after consideration
of several other proposals. None of these was found satisfactory. Following
is an overview some of these proposals, which is in turn followed by a discussion
of the characteristics of the <tt>bool</tt> type.</p>
<h4> typedef Boolean</h4>
<p>One suggestion was to use a <tt>typedef</tt> for a Boolean data type:</p>
<pre>
<tt>typedef int bool;</tt>
</pre>
<p>However, a <tt>typedef</tt> that relies on another built-in type of the
language renders the Boolean type unusable with some language features.
For example, using it in function overloading can result in ambiguities:</p>
<pre>
<tt>void f(bool);</tt>
<tt>void f(int);//error, redefinition of void f(bool);</tt>
</pre>
<p>In addition, a <tt>typedef</tt> is not strongly-typed. Consequently, it
is impossible to ensure that only Boolean values are assigned to it in a
context that requires Boolean values.</p>
<h4> enum Type</h4>
<p>An alternative solution was to use an <tt>enum</tt> type:</p>
<pre>
<tt>enum bool { false, true};</tt>
</pre>
<p><tt>enum</tt>s are strongly-typed. However, the committee wanted to ensure
backward compatibility with old code that used <tt>int</tt> values as a
Boolean data type. For example</p>
<pre>
<tt>#include <ctype.h></tt>
<tt>enum bool {false, true};</tt>
<tt>void f()</tt>
<tt>{</tt>
<tt> enum bool b;</tt>
<tt> b = islower('a'); //compile time error, int assigned to an enum</tt>
<tt>}</tt>
</pre>
<h4> Class bool</h4>
<p>A third suggestion was to use a class such as the following:</p>
<pre>
<tt>class bool</tt>
<tt>{</tt>
<tt>private:</tt>
<tt> int val;</tt>
<tt>public:</tt>
<tt> operator int();</tt>
<tt>};</tt>
</pre>
<p>Such a class guarantees type uniqueness, so it can be used to overload
functions and to specialize templates. In addition, it is backward compatible
with Boolean integers. There are, however, several drawbacks to the class
approach. First, users are required to <tt>#include</tt> a dedicated header
and to link their programs with the compiled code of the class. Worse yet,
the conversion operator might interfere with user-defined conversion operators
that are defined in other classes. Finally, a full-blown class that defines
constructors and conversion operators is significantly less efficient than
a fundamental type. For these reasons, the Standardization committee decided
to add a new built-in type.</p>
<h4> A Built-in Type bool</h4>
<p><tt>bool</tt> is an implementation-dependent integral type that can hold
either a <tt>true</tt> or a <tt>false</tt> value. A standardized Boolean
type has several advantages:</p>
<ul>
<li>
<p> <b>Portability</b> -- All Standard compliant compilers support <tt>bool</tt>
type. When code is ported to different platforms, it will work as expected.</p>
</li>
<p></p>
<li> <b>Readability</b> -- The use of explicit keywords such as <tt>true</tt>,
<tt>false</tt>, and <tt>bool</tt> is self-documenting and is more evident
than the use of <tt>int</tt> values.</li>
<p></p>
<li> <b>Type Distinctness</b> -- Because <tt>bool</tt> is a distinct type,
the following functions are now also distinct:</li>
</ul>
<p></p>
<pre>
<tt>void f(bool b);</tt>
<tt>void f(int n);</tt>
</pre>
<ul>
<li> <b>Performance</b> -- Memory usage can be optimized by the implementation,
which is allowed to use a single byte to represent a <tt>bool</tt> instead
of an <tt>int</tt>. In addition, the use of a built-in type rather than
a class also ensures the highest performance.</li>
</ul>
<p></p>
<p>With the introduction of the <tt>bool</tt> data type, built-in operators
were modified accordingly to work with <tt>bool</tt> values. The logical
operators <tt>&&</tt>, <tt>||</tt>, and <tt>!</tt> now take <tt>bool</tt>
values as arguments and return <tt>bool</tt> results. Similarly, the relational
operators <tt><</tt>, <tt>></tt>, <tt><=</tt>, <tt>>=</tt>,
<tt>==</tt>, and <tt>!=</tt> return <tt>bool</tt> results. In addition,
<tt>iostream</tt> classes were adjusted to support the new type.</p>
<p><b>(f)Viewing <tt>bool</tt> Variables as Literals</b></p>
<p>By default, <tt>iostream</tt> objects display <tt>bool</tt> variables as
<tt>0</tt> and <tt>1</tt>. It is possible to override the default setting
by inserting the formatting flag <tt>boolalpha</tt> to the stream object.
Subsequently, the symbolic representations <tt>false</tt> and <tt>true</tt>
are displayed instead of <tt>0</tt> and <tt>1</tt>. For example</p>
<pre>
<tt>#include <iostream></tt>
<tt>using namespace std;</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt> bool b = true;</tt>
<tt> cout<<b; // default setting; display 1</tt>
<tt> cout<<boolalpha; //henceforth, display 'true' and 'false' instead of 1 and 0</tt>
<tt> cout<<b; // output: true</tt>
<tt> cout<<!b; // output: false</tt>
<tt> return 0;</tt>
<tt>}</tt>
</pre>
<h3> <a name="Heading17">Exception Handling</a></h3>
<p>Exception handling is used to report and handle runtime errors. Supplementary
features, namely <i>exception specifications</i> and <i>function </i><tt>try</tt><i>
blocks</i>, were added to the Standard in recent years. The following sections
provide a brief overview of these features. (Exception handling and the
supplementary features are discussed in more detail in Chapter 6, "Exception
Handling.")</p>
<h4> Exception Specification</h4>
<p>A function can indicate the potential exceptions it can throw by specifying
a list of these exceptions. Exception specifications are particularly useful
when users of such a function can only view its prototype but cannot access
its source file. Following is an example of specifying an exception:</p>
<pre>
<tt>class Zerodivide{/*..*/};</tt>
<tt>int divide (int, int) throw(Zerodivide); //function may throw an exception</tt>
<tt> //of type Zerodivide, but no other</tt>
</pre>
<h4> Function try Blocks</h4>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -