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

📄 ch02.htm

📁 c++语言操作手册
💻 HTM
📖 第 1 页 / 共 5 页
字号:
      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 = &amp;cnum;</tt><tt>int *pi  = const_cast&lt;int*&gt; (pci); // brute force attempt to unconst a variable</tt><tt>cout&lt;&lt; *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 = &amp;num;  // *pci is a contractual const int</tt><tt> int *pi  = const_cast&lt;int*&gt; (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 &lt;</tt><cite>to</cite><tt>&gt; (</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 &lt;cstdio&gt;</tt><tt>void mem_probe()</tt><tt>{</tt><tt>  long n = 1000000L; long *pl = &amp;n;</tt><tt>  unsigned char * pc = reinterpret_cast &lt;unsigned char *&gt; (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&lt;void *&gt; (0x00fffd);</tt><tt> int ptr = reinterpret_cast&lt;int&gt; (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&lt;C*&gt; (pb); //correct offset adjustment</tt><tt>  C *pc2 = reinterpret_cast&lt;C*&gt; (pb); //no offset calculated</tt><tt>}</tt><tt>int main()</tt><tt>{</tt><tt> B b;</tt><tt> func(&amp;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&lt;derived *&gt; (&amp;base); //pointer form</tt><tt>Derived &amp; rd  = dynamic_cast&lt;derived &amp;&gt; (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 &lt;ctype.h&gt;</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>&amp;&amp;</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>&lt;</tt>, <tt>&gt;</tt>, <tt>&lt;=</tt>, <tt>&gt;=</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 &lt;iostream&gt;</tt><tt>using namespace std;</tt><tt>int main()</tt><tt>{</tt><tt>  bool b = true;</tt><tt>  cout&lt;&lt;b;  // default setting; display 1</tt><tt>  cout&lt;&lt;boolalpha; //henceforth, display 'true' and 'false' instead of 1 and 0</tt><tt>  cout&lt;&lt;b;   // output: true</tt><tt>  cout&lt;&lt;!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>    <p>A <i>function </i><tt>try</tt><i> block</i> is a function whose body consists       of a <tt>try</tt> block and its associated handlers. A function <tt>try</tt>       block enables you to catch exceptions that might be thrown by a base class       constructor or by a constructor of a member object. The original specification       of exception handling did not enable users to handle exceptions thrown from       a constructor or a member initialization list locally; a function <tt>try</tt> 

⌨️ 快捷键说明

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