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

📄 ch02.htm

📁 c++语言操作手册
💻 HTM
📖 第 1 页 / 共 5 页
字号:
      by the C++ Standard, usually to allow efficient and simple compiler implementation       on various platforms. Conversely, undefined behavior is always undesirable       and should never occur.</p>    <h3> <a name="Heading11">The One Definition Rule</a></h3>    <p>A class, an enumeration, an inline function with external linkage, a class       template, a nonstatic function template, a member function template, a static       data member of a class template, or a template specialization for which       some template parameters are not specified can be defined more than once       in a program -- provided that each definition appears in a different translation       unit, and provided that the definitions meet the requirements that are detailed       in the following sections.</p>    <h4> Token-by-Token Identity</h4>    <p>Each definition must contain the same sequence of tokens. For example</p>    <pre><tt>  //file fisrt.cpp</tt><tt>inline int C::getVal () { return 5; }</tt><tt>  //file sec.cpp</tt><tt>typedef int I;</tt><tt>inline I C::getVal () { return 5; } // violation of ODR, </tt><tt>                                    // I and int are not identical tokens</tt></pre>    <p>On the other hand, white spaces and comments are immaterial:</p>    <pre><tt>  //file fisrt.cpp</tt><tt>inline int C::getVal () { return 5; }</tt><tt>  //file sec.cpp</tt><tt>inline int C::getVal () { /*complies with the ODR*/</tt><tt>return 5; }</tt></pre>    <h4> Semantic Equivalence</h4>    <p>Each token in the identical sequences of the separate definitions has the       same semantic contents. For example</p>    <pre><tt>//file first.cpp</tt><tt>typedef int I;</tt><tt>inline I C::getVal () { return 5; }</tt><tt>//file second.cpp</tt><tt>typedef unsigned int I;</tt><tt>inline I C::getVal () { return 5; } //error; different semantic content for I</tt></pre>    <h3> <a name="Heading12">Linkage Types</a></h3>    <p>A name that refers to an object, reference, type, function, template, namespace,       or value that is declared in another scope is said to have <i>linkage</i>.       The linkage can be either <i>external </i>or <i>internal</i>. Otherwise,       the name has no linkage.</p>    <h4> External Linkage</h4>    <p>A name that can be referred to from other translation units or from other       scopes of the translation unit in which it was defined has <i>external linkage</i>.       Following are some examples:</p>    <pre><tt>void g(int n) {} //g has external linkage</tt><tt>int glob; //glob has external linkage</tt><tt>extern const int E_MAX=1024; //E_MAX has external linkage</tt><tt>namespace N</tt><tt>{</tt><tt>  int num;  //N::num has external linkage</tt><tt>  void func();//N::func has external linkage</tt><tt>}</tt><tt>class C {}; //the name C has external linkage</tt></pre>    <h4> Internal Linkage</h4>    <p>A name that can be referred to by names from other scopes in the translation       unit in which it was declared, but not from other translation units, has       <i>internal linkage</i>. Following are some examples:</p>    <pre><tt>static void func() {} //func has internal linkage</tt><tt>union //members of a non-local anonymous union have internal linkage</tt><tt>{</tt><tt>  int n;</tt><tt>  void *p;</tt><tt>};</tt><tt>const int MAX=1024; //non-extern const variables have internal linkage</tt><tt>typedef int I; //typedefs have internal linkage</tt></pre>    <h4> Names With No Linkage</h4>    <p>A name that can only be referred to from the scope in which it is declared       has no linkage. For example</p>    <pre><tt>void f()</tt><tt>{</tt><tt>  int a; //a has no linkage</tt><tt>  class B {/**/}; //a local class has no linkage</tt><tt>}</tt></pre>    <h3> <a name="Heading13">Side effect</a></h3>    <p>A <i>side effect</i> is a change in the state of the execution environment.       Modifying an object, accessing a <tt>volatile</tt> object, invoking a library       I/O function, and calling a function that performs any of these operations       are all side effects.</p>    <h2> <a name="Heading14">Addenda</a></h2>    <p>This part details the new features -- and extensions to existing features       -- that have been adopted by the C++ Standard in recent years.</p>    <h3> <a name="Heading15">New Typecast Operators</a></h3>    <p>C++ still supports C-style cast, as in</p>    <pre><tt>int i = (int) 7.333;</tt></pre>    <p>Nonetheless, C-style cast notation is problematic for several reasons.       First, the operator <tt>()</tt> is already used excessively in the language:       in a function call, in precedence reordering of expressions, in operator       overloading, and in other syntactic constructs. Second, C-style cast carries       out different operations in different contexts -- so different that you       can hardly tell which is which. It can perform an innocuous standard cast,       such as converting an <tt>enum</tt> value to an <tt>int</tt>; but it can       also cast two nonrelated types to one another. In addition, a C-style cast       can be used to remove the <tt>const</tt> or <tt>volatile</tt> qualifiers       of an object (and in earlier stages of C++, the language was capable of       performing dynamic casts as well).</p>    <p>Because of these multiple meanings, the C-style cast is opaque. Sometimes       it is very difficult for a reader to clearly understand the intent of the       code author who uses a C-style cast operation. Consider the following example:</p>    <pre><tt>#include &lt;iostream&gt;</tt><tt>using namespace std;</tt><tt>void display(const unsigned char *pstr)</tt><tt>{</tt><tt>  cout&lt;&lt;pstr&lt;&lt;endl;</tt><tt>}</tt><tt>void func()</tt><tt>{</tt><tt>  const char * p = "a message";</tt><tt>  display( (unsigned char*) p); //signed to unsigned cast is required</tt><tt>                                // but const is also removed. was that</tt><tt>                                // intentional or a programmer's oversight?</tt><tt>}</tt></pre>    <p>The new cast operators make the programmer's intention clearer and self-documenting.       In addition, they enable the compiler to detect mistakes that cannot be       detected with C-style cast. The new cast operators are intended to replace       C-style cast; C++ programmers are encouraged to use them instead of C-style       cast notation. These operators are detailed in the following sections.</p>    <h4> static_cast</h4>    <p><tt>static_cast</tt> &lt;<cite>Type</cite><tt>&gt; (</tt><cite>Expr</cite><tt>)</tt>       performs well-behaved and reasonably well-behaved casts. One of its uses       is to indicate explicitly a type conversion that is otherwise performed       implicitly by the compiler. </p>    <p>For example</p>    <pre><tt>class Base{};</tt><tt>class Derived : public Base {};</tt><tt>void func( Derived * pd)</tt><tt>{</tt><tt> Base * pb = static_cast&lt;Base *&gt; (pd); //explicit</tt><tt>}</tt></pre>    <p>A pointer to a derived object can be automatically converted to a pointer       to a public base. The use of an explicit cast makes the programmer's intent       clearer.</p>    <p><tt>static_cast</tt> can be used to document user-defined conversion. For       example</p>    <pre><tt>class Integer</tt><tt>{</tt><tt>  public: operator int ();</tt><tt>};</tt><tt>void func(Integer&amp; integer)</tt><tt>{</tt><tt> int num = static_cast&lt;int&gt; (integer); //explicit</tt><tt>}</tt></pre>    <p>Narrowing conversions of numeric types can also be performed explicitly       by a <tt>static_cast</tt>. For example</p>    <pre><tt>void func()</tt><tt>{</tt><tt>  int num = 0;</tt><tt>  short short_num = static_cast&lt;short&gt; (num);</tt><tt>}</tt></pre>    <p>This conversion is somewhat riskier than the previous conversions. A <tt>short</tt>       might not represent all the values that an <tt>int</tt> can hold; an explicit       cast is used here, instead of an implicit conversion, to indicate that a       type conversion is performed. Casting an integral value to an <tt>enum</tt>       is also a dangerous operation because there is no guarantee that the value       of an <tt>int</tt> can be represented in an <tt>enum</tt>. Note that in       this case, an explicit cast is necessary:</p>    <pre><tt>void func()</tt><tt>{</tt><tt>  enum status {good, bad};</tt><tt>  int num = 0;</tt><tt>  status s = static_cast&lt;status&gt; (num);</tt><tt>}</tt></pre>    <p>You can use <tt>static_cast</tt> to navigate through class hierarchies.       Unlike <tt>dynamic_cast</tt>, however, it relies solely on the information       that is available at compile time -- so don't use it instead of <tt>dynamic_cast</tt>.       Using <tt>static_cast</tt> for this purpose is safer than using C-style       cast because it does not perform conversions between nonrelated classes.       For example</p>    <pre><tt>class A{};</tt><tt>class B{};</tt><tt>A *pa;</tt><tt>B * pb = static_cast&lt;B *&gt; (pa); //error, pointers are not related</tt></pre>    <h4> const_cast</h4>    <p><tt>const_cast &lt;T&gt; (Expr)</tt> removes only the <tt>const</tt> or       <tt>volatile</tt> qualifiers of <tt>Expr</tt> and converts them to type       <tt>T</tt>. <tt>T</tt> must be the same type of <tt>Expr</tt>, except for       the missing <tt>const</tt> or <tt>volatile</tt> attributes. For example</p>    <pre><tt>#include &lt;iostream&gt;</tt><tt>using namespace std;</tt><tt>void print(char *p) //parameter should have been declared as const; alas,</tt><tt>{</tt><tt>  cout&lt;&lt;p;</tt><tt>}</tt><tt>void f()</tt><tt>{</tt><tt>  const char msg[] = "Hello World\n";</tt><tt>  char * p = const_cast&lt;char *&gt; (msg); //remove constness</tt><tt>  print(p);</tt><tt>}</tt></pre>    <p><tt>const_cast</tt> can also convert an object to a <tt>const</tt> or <tt>volatile</tt>       one:</p>    <pre><tt>void read(const volatile int * p);</tt><tt>int *p = new int;		 </tt><tt>read( const_cast&lt;const volatile int *&gt; (p) ); //explicit </tt></pre>    <p>Note that the removal of the <tt>const</tt> qualifier of an object does       not guarantee that its value can be modified; it only guarantees that it       can be used in a context that requires a non-<tt>const</tt> object. So that       you understand these limitations, the following sections examines <tt>const</tt>       semantics in further detail.</p>    <p><b>(f)<tt>const</tt> Semantics</b></p>    <p>There are actually two types of <tt>const</tt>: <i>true</i> <tt>const</tt>       and <i>contractual</i> <tt>const</tt>. A true <tt>const</tt> object is an       lvalue that was originally defined as <tt>const</tt>. For example</p>    <pre><tt>const int cn = 5; // true const</tt><tt>const std::string msg("press any key to continue"); // true const</tt></pre>    <p>On the other hand, an object with contractual <tt>const</tt> quality is       one that was defined without the <tt>const</tt> qualifier, but that is treated       as though it were <tt>const</tt>. For example</p>    <pre><tt>void ReadValue(const int&amp; num)</tt><tt>{</tt><tt>  cout&lt;&lt;num;  // num may not be modified in ReadValue()</tt><tt>}</tt><tt>int main()</tt><tt>{</tt><tt>  int n =0;</tt><tt>  ReadValue(n); //contractual const, n is treated as if it were const</tt><tt>}</tt></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 

⌨️ 快捷键说明

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