📄 index.html
字号:
<p>Unspecified behavior and implementation-defined behavior are consistent
-- albeit nonportable -- behaviors that are left intentionally unspecified
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 <iostream></tt>
<tt>using namespace std;</tt>
<tt>void display(const unsigned char *pstr)</tt>
<tt>{</tt>
<tt> cout<<pstr<<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> <<cite>Type</cite><tt>> (</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<Base *> (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& integer)</tt>
<tt>{</tt>
<tt> int num = static_cast<int> (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<short> (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<status> (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<B *> (pa); //error, pointers are not related</tt>
</pre>
<h4> const_cast</h4>
<p><tt>const_cast <T> (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 <iostream></tt>
<tt>using namespace std;</tt>
<tt>void print(char *p) //parameter should have been declared as const; alas,</tt>
<tt>{</tt>
<tt> cout<<p;</tt>
<tt>}</tt>
<tt>void f()</tt>
<tt>{</tt>
<tt> const char msg[] = "Hello World\n";</tt>
<tt> char * p = const_cast<char *> (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<const volatile int *> (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& num)</tt>
<tt>{</tt>
<tt> cout<<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>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -