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

📄 index.html

📁 C程序员手册(英文)
💻 HTML
📖 第 1 页 / 共 3 页
字号:
  Note that these rules do not apply to the assignment operator, which is implicitly 
  declared for a class if it is not declared by the user. Therefore, a base class 
  assignment operator is always hidden by the copy assignment operator of the 
  derived class. (The assignment operator is discussed in Chapter 4, "Special 
  Member Functions: Default Constructor, Copy Constructor, Destructor, and Assignment 
  Operator.")</p>
<h3> <a name="Heading7">Operators Can Only Be Overloaded for User-Defined Types 
  </a></h3>
<p>An overloaded operator must take at least one argument of a user-defined type 
  (operators <tt>new</tt> and <tt>delete</tt> are an exception -- see Chapter 
  11, "Memory Management," for more details). This rule ensures that users cannot 
  alter the meaning of expressions that contain only fundamental types. For example</p>
<pre>
<tt>int i,j,k;</tt>
<tt>k = i + j; //always uses built-in = and +</tt>
</pre>
<p></p>
<h3> <a name="Heading8">Invention of New Operators Is Not Allowed</a></h3>
<p>An overloaded operator extends a built-in one, so you cannot introduce new 
  operators into the language (conversion operators differ from ordinary overloaded 
  operators in this respect). The following example attempts to overload the <tt>@</tt> 
  operator, but does not compile for that reason:</p>
<pre>
<tt>void operator @ (int); //illegal, @ is not a built-in operator or a type name</tt>
</pre>
<h3> <a name="Heading9"> Precedence and Argument Number</a></h3>
<p>Neither the precedence nor the number of arguments of an operator can be altered. 
  For example, an overloaded <tt>&amp;&amp;</tt> must have exactly two arguments 
  -- as does the built-in <tt>&amp;&amp;</tt> operator. In addition, the precedence 
  of an operator cannot be altered when it is overloaded. A sequence of two or 
  more overloaded operators, for instance <tt>t2&lt;t1/t2</tt>, is evaluated according 
  to the precedence rules of the built-in operators. Because the division operator 
  ranks higher than the less operator, the expression is always interpreted as 
  <tt>t2&lt;(t1/t2)</tt>.</p>
<h3> <a name="Heading10">Default Parameters</a></h3>
<p>Unlike ordinary functions, overloaded operators cannot declare a parameter 
  with a default value (operator <tt>()</tt> is the exception to this rule; it 
  is discussed later).</p>
<pre>
<tt>class Date</tt>
<tt>{</tt>
<tt>private:</tt>
<tt>  int day;</tt>
<tt>  int month; </tt>
<tt>  int year;</tt>
<tt>public:</tt>
<tt>  Date &amp; operator += (const Date &amp; d = Date() ); //error, default argument</tt>
<tt>};</tt>
</pre>
<p>This rule might seem arbitrary, but it captures the behavior of built-in operators, 
  which never have default operands either.</p>
<h3> <a name="Heading11">Operators That Cannot Be Overloaded</a></h3>
<p>There are several operators that cannot be overloaded. They are characterized 
  by the fact that they take a name, rather than an object, as their right operand. 
  These operators are:</p>
<ul>
  <li>Direct member access, operator <tt>.</tt></li>
  <p></p>
  <li> 
    <p> Deference pointer to class member, operator <tt>.*</tt></p>
  </li>
  <p></p>
  <li> Scope resolution, operator <tt>::</tt></li>
  <p></p>
  <li> Size of, operator <tt>sizeof</tt></li>
</ul>
<p></p>
<p>The conditional operator <tt>?:</tt> cannot be overloaded either.</p>
<p>Additionally, the new type cast operators -- <tt>static_cast&lt;&gt;</tt>, 
  <tt>dynamic_cast&lt;&gt;</tt>, <tt>reinterpret_cast&lt;&gt;</tt>, and <tt>const_cast&lt;&gt;</tt> 
  -- and the <tt>#</tt> and <tt>##</tt> preprocessor tokens cannot be overloaded.</p>
<h2> <a name="Heading12">Conversion Operators</a></h2>
<p>It is not uncommon to find C++ and C code used together. For instance, legacy 
  systems that were originally written in C can be wrapped by an object-oriented 
  interface. Such bilingual systems often need to support a dual interface at 
  the same time -- one that caters to an object-oriented environment and another 
  that caters to C environment. Classes that implement specific numeric entities 
  -- such as complex numbers and binary numbers -- and nibbles also tend to use 
  conversion operators to enable smoother interaction with fundamental types.</p>
<p>Strings are a classic example of the need for a dual interface. A string object 
  might have to be used in contexts that support only null-terminated <tt>char</tt> 
  arrays. For example</p>
<pre>
<tt>class Mystring</tt>
<tt>{</tt>
<tt>private:</tt>
<tt>  char *s;</tt>
<tt>  int size;</tt>
<tt>public:</tt>
<tt>  Mystring(const char *);</tt>
<tt>  Mystring();</tt>
<tt>//...</tt>
<tt>};</tt>
<tt>#include &lt;cstring&gt;</tt>
<tt>#include "Mystring.h"</tt>
<tt>using namespace std;</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt>  Mystring str("hello world");</tt>
<tt> int n = strcmp(str, "Hello");  //compile time error: </tt>
<tt>                                 //str is not of  type const char *</tt>
<tt>  return 0;</tt>
<tt>}</tt>
</pre>
<p>C++ offers an automatic means of type conversion for such cases. A conversion 
  operator can be thought of as a user-defined typecasting operator; it converts 
  its object to a different type in contexts that require that specific type. 
  The conversion is done automatically. For example</p>
<pre>
<tt>class Mystring   //now with conversion operator</tt>
<tt>{</tt>
<tt>private:</tt>
<tt>  char *s;</tt>
<tt>  int size;</tt>
<tt>public:</tt>
<tt>  Mystring();</tt>
<tt>  operator const char * () {return s; } //convert Mystring  to a C-string</tt>
<tt>//...</tt>
<tt>};</tt>
<tt>int n = strcmp(str, "Hello<cite>"); </cite>//OK, automatic conversion of str to const char *</tt>
</pre>
<p>Conversion operators differ from ordinary overloaded operators in two ways. 
  First, a conversion operator does not have a return value (not even <tt>void</tt>). 
  The return value is deduced from the operator's name. </p>
<p>Secondly, a conversion operator takes no arguments.</p>
<p>Conversion operators can convert their object to any given type, fundamental 
  and user-defined alike:</p>
<pre>
<tt>struct DateRep  //legacy C code</tt>
<tt>{</tt>
<tt>  char day;</tt>
<tt>  char month;</tt>
<tt>  short year;</tt>
<tt>};</tt>
<tt>class Date // object-oriented wrapper</tt>
<tt>{</tt>
<tt>private:</tt>
<tt>  DateRep dr;</tt>
<tt>public:</tt>
<tt>  operator DateRep () const { return dr;} // automatic conversion to DateRep</tt>
<tt>};</tt>
<tt>extern "C" int transmit_date(DateRep);  // C-based communication API function</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt>  Date d;</tt>
<tt>  //...use d</tt>
<tt>  //transmit date object as a binary stream to a remote client</tt>
<tt>  int ret_stat = transmit_date; //using legacy communication API</tt>
<tt>  return 0;</tt>
<tt>}</tt>
</pre>
<h3> <a name="Heading13">Standard Versus User-Defined Conversions</a></h3>
<p>The interaction of a user-defined conversion with a standard conversion can 
  cause undesirable surprises and side effects, and therefore must be used with 
  caution. Examine the following concrete example.</p>
<p>A non-<tt>explicit</tt> constructor that takes a single argument is also a 
  conversion operator, which casts its argument to an object of this class. When 
  the compiler has to resolve an overloaded function call, it takes into consideration 
  such user-defined conversions in addition to the standard ones. For example</p>
<pre>
<tt>class Numeric</tt>
<tt>{</tt>
<tt>private:</tt>
<tt>  float f;</tt>
<tt>public:</tt>
<tt>  Numeric(float ff): f(ff) {} //constructor is also a float-to-Numeric </tt>
<tt>                              // conversion operator</tt>
<tt>};</tt>
<tt>void f(Numeric);</tt>
<tt>Numeric num(0.05);</tt>
<tt>f(5.f);  //OK, calls void f(Numeric). Numeric's constructor </tt>
<tt>         //converts argument to a Numeric object</tt>
</pre>
<p>'Suppose you add, at a later stage, another overloaded version of <tt>f()</tt>:</p>
<pre>
<tt>void f (double);</tt>
</pre>
<p>Now the same function call resolves differently:</p>
<pre>
<tt>f(5.f); // now calls f(double), not f(Numeric)</tt>
</pre>
<p>This is because <tt>float</tt> is promoted to <tt>double</tt> automatically 
  in order to match an overloaded function signature. This is a standard type 
  conversion. On the other hand, the conversion of <tt>float</tt> to <tt>Numeric</tt> 
  is a user-defined conversion. User-defined conversions rank lower than standard 
  conversions -in overload resolution; as a result, the function call resolves 
  differently.</p>
<p>Because of this phenomenon and others, conversion operators have been severely 
  criticized. Some programming schools ban their usage altogether. However, conversion 
  operators are a valuable -- and sometimes inevitable -- tool for bridging between 
  dual interfaces, as you have seen.</p>
<h2> <a name="Heading14">Postfix and Prefix Operators</a></h2>
<p>For primitive types, C++ distinguishes between <tt>++x;</tt> and <tt>x++;</tt> 
  as well as between <tt>--x;</tt> and <tt>x--;</tt>. Under some circumstances, 
  objects have to distinguish between prefix and postfix overloaded operators 
  as well (for example, as an optimization measure. See Chapter 12, "Optimizing 
  Your Code"). Postfix operators are declared with a dummy <tt>int</tt> argument, 
  whereas their prefix counterparts take no arguments. For example</p>
<pre>
<tt>class Date</tt>
<tt>{</tt>
<tt>public:</tt>
<tt>  Date&amp; operator++(); //prefix</tt>
<tt>  Date&amp; operator--(); //prefix</tt>
<tt>  Date&amp; operator++(int unused); //postfix</tt>
<tt>  Date&amp; operator--(int unused); //postfix</tt>
<tt>};</tt>
<tt>void f()</tt>
<tt>{</tt>
<tt>Date d, d1;</tt>
<tt>d1 = ++d;//prefix: first increment d and then assign to d1</tt>
<tt>d1 = d++; //postfix; first assign, increment d afterwards</tt>
<tt>}</tt>
</pre>
<h2> <a name="Heading15">Using Function Call Syntax</a></h2>
<p>An overloaded operator call is merely "syntactic sugar" for an ordinary function 
  call. You can use the explicit function call instead of the operator syntax 
  as follows: </p>
<pre>
<tt>bool operator==(const Date&amp; d1, const Date&amp; d2);</tt>
<tt>void f()</tt>
<tt>{</tt>
<tt>  Date d, d1;</tt>
<tt>  bool equal;</tt>
<tt>  d1.operator++(0); // equivalent to: d1++;</tt>
<tt>  d1.operator++(); // equivalent to: ++d1;</tt>
<tt>  equal = operator==(d, d1);// equivalent to: d==d1; </tt>
<tt>  Date&amp;(Date::*pmf) (); //pointer to member function</tt>
<tt>  pmf = &amp; Date::operator++;</tt>
<tt>} </tt>
</pre>
<h2> <a name="Heading16">Consistent Operator Overloading</a></h2>
<p>Whenever you overload operators such as <tt>+</tt> or <tt>-</tt>, it might 
  become necessary to support the corresponding <tt>+=</tt> and <tt>-=</tt> operators 
  as well. The compiler does not do that for you automatically. Consider the following 
  example:</p>
<pre>
<tt>class Date</tt>
<tt>{</tt>
<tt>public:</tt>
<tt>  Date&amp; operator + (const Date&amp; d);  //note: operator += not defined</tt>
<tt>};</tt>
<tt>Date d1, d2;</tt>
<tt>d1 = d1 + d2; //fine; uses overloaded + and default assignment operator</tt>
<tt>d1 += d2; //compile time error: 'no user defined operator += for class Date'</tt>
</pre>
<p>Theoretically, the compiler could synthesize a compound operator <tt>+=</tt> 
  by combing the assignment operator and the overloaded <tt>+</tt> operator so 
  that the expression <tt>d1 += d2;</tt> is automatically expanded into <tt>d1 
  = d1+d2;.</tt> However, this is undesirable because the automatic expansion 
  might be less efficient than a user-defined version of the operator. An automated 
  version creates a temporary object, whereas a user-defined version can avoid 
  it. Moreover, it is not difficult to think of situations in which a class has 
  an overloaded operator <tt>+</tt>, but does not have operator <tt>+=</tt> intentionally.</p>

⌨️ 快捷键说明

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