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

📄 ch03.htm

📁 c++语言操作手册
💻 HTM
📖 第 1 页 / 共 3 页
字号:
<h2> <a name="Heading17"> Returning Objects by Value</a></h2><p>For the sake of efficiency, large objects are usually passed to -- or returned   from -- a function by reference or by their address. There are, however, a few   circumstances in which the best choice is still to return an object by value.   Operator <tt>+</tt> is an example of this situation. It has to return a result   object, but it cannot modify any of its operands. The seemingly natural choice   is to allocate the result object on the free store and return its address. Nevertheless,   this is not such a good idea. Dynamic memory allocation is significantly slower   than local storage. It also might fail and throw an exception, which then has   to be caught and handled. Even worse, this solution is error prone because it   is unclear who is responsible for deleting this object -- the creator or the   user?</p><p>Another solution is to use a static object and return it by reference. For   example</p><pre><tt>class Year</tt><tt>{</tt><tt>private:</tt><tt>  int year;</tt><tt>public:</tt><tt>  Year(int y = 0) : year(y) {}</tt><tt>  Year&amp; operator + (const Year&amp; other) const; //returns a reference to </tt><tt>                                              //a local static Year</tt><tt>  int getYear() const;</tt><tt>  void setYear(int y);</tt><tt>};</tt><tt>Year&amp; Year::operator + (const Year&amp; other) const  </tt><tt>{ </tt><tt>  static Year result;</tt><tt>  result = Year(this-&gt;getYear() + other.getYear() ); </tt><tt>  return result;</tt><tt>}</tt></pre><p>Static objects solve the ownership problem, but they are still problematic:   On each invocation of the overloaded operator, the same instance of the static   object is being modified and returned to the caller. The same object can be   returned by reference to several more users, who do not know that they are holding   a shared instance that has just been modified behind their back.</p><p>Finally, the safest and most efficient solution is still to return the result   object by value:</p><pre><tt>class Year</tt><tt>{</tt><tt>private:</tt><tt>  int year;</tt><tt>public:</tt><tt>  Year(int y = 0) : year(y) {}</tt><tt>  Year operator + (const Year&amp; other) const; //return Year object by value</tt><tt>  int getYear() const;</tt><tt>  void setYear(int y);</tt><tt>};</tt><tt>Year Year::operator + (const Year&amp; other) const</tt><tt>{ </tt><tt>  return Year(this-&gt;getYear() + other.getYear() );  </tt><tt>}</tt></pre><h2> <a name="Heading18">Multiple Overloading</a></h2><p>Overloaded operators obey the rules of function overloading. Therefore, it   is possible to overload an operator more than once. When is it useful? Consider   the following <tt>Month</tt> class and its associated operator<tt> ==</tt>:</p><pre><tt>class Month</tt><tt>{</tt><tt>private:</tt><tt>  int m;</tt><tt>public:</tt><tt>  Month(int m = 0); </tt><tt>};</tt><tt>bool operator == (const Month&amp; m1, const Month &amp;m2);</tt></pre><p>It is possible to use the overloaded operator <tt>==</tt> to compare a plain   <tt>int</tt> value and a <tt>Month</tt> object due to the implicit conversion   of <tt>int</tt> to <tt>Month</tt>. For example</p><pre><tt>void f()</tt><tt>{</tt><tt>  int n = 7;</tt><tt>  Month June(6);</tt><tt>  bool same = </tt><tt>    (June == n); //calls bool operator == (const Month&amp; m1, const Month &amp;m2);</tt><tt>}</tt></pre><p>This works fine, but it i's inefficient: The argument <tt>n</tt> is first converted   to a temporary <tt>Month</tt> object, which is then compared with the object   <tt>June</tt>. You can avoid the unnecessary construction of a temporary object   by defining additional overloaded versions of operator <tt>==</tt>:</p><pre><tt>bool operator == (int m, const Month&amp; month);</tt><tt>bool operator == (const Month&amp; month, int m);</tt></pre><p>Consequently, the expression <tt>June == n</tt> will now invoke the following   overloaded operator:</p><pre><tt>bool operator == (const Month&amp; month, int m);</tt></pre><p>This overloaded version does not create a temporary object, so it's more efficient.   The same performance considerations led the C++ Standardization committee to   define three distinct versions of operator <tt>==</tt> for <tt>std::string</tt>   (see Chapter 10, ""STL and Generic Programming"") and other classes of the Standard   Library.' </p><h2> <a name="Heading19">Overloading Operators for Other User-Defined types</a></h2><p>You can overload an operator for <tt>enum</tt> types as well. For example,   it may be useful to overload operators such as ++ and <tt>--</tt> so that they   can iterate through the enumerator values of a given <tt>enum</tt> type. You   can do it like this:</p><pre><tt>#include &lt;iostream&gt;</tt><tt>using namespace std;</tt><tt>enum Days </tt><tt>{</tt><tt>  Monday, </tt><tt>  Tuesday,</tt><tt>  Wednesday, </tt><tt>  Thursday, </tt><tt>  Friday, </tt><tt>  Saturday, </tt><tt>  Sunday</tt><tt>};</tt><tt>Days&amp; operator++(Days&amp; d, int)  // postfix ++</tt><tt>{</tt><tt>  if (d == Sunday) </tt><tt>    return d = Monday; //rollover</tt><tt>  int temp = d; //convert to an int</tt><tt>  return d = static_cast&lt;Days&gt; (++temp); </tt><tt>}</tt><tt>int main()</tt><tt>{</tt><tt> Days day = Monday;</tt><tt> for (;;) //display days as integers</tt><tt> {</tt><tt>   cout&lt;&lt; day &lt;&lt;endl;</tt><tt>   day++;</tt><tt>   if (day == Sunday) </tt><tt>     break;</tt><tt> }</tt><tt> return 0;</tt><tt>}</tt></pre><p>If you prefer to view the enumerators in their symbolic representation rather   than as integers, you can overload the operator <tt>&lt;&lt;</tt> as well:</p><pre><tt>ostream&amp; operator&lt;&lt;(ostream&amp; os, Days d) //display Days in symbolic form</tt><tt>{</tt><tt>  switch</tt><tt>  {</tt><tt>  case Monday:</tt><tt>    return os&lt;&lt;"Monday";</tt><tt>  case Tuesday:</tt><tt>    return os&lt;&lt;"Tuesday";</tt><tt>  case Wednesday:</tt><tt>    return os&lt;&lt;"Wednesday";</tt><tt>  case Thursday:</tt><tt>    return os&lt;&lt;"Thursady";</tt><tt>  case Friday:</tt><tt>    return os&lt;&lt;"Friday";</tt><tt>  case Saturday:</tt><tt>    return  os&lt;&lt;"Satrurday";</tt><tt>  case Sunday:</tt><tt>    return os&lt;&lt;"Sunday";</tt><tt>  default:</tt><tt>    return os&lt;&lt;"Unknown";</tt><tt>  } </tt><tt>}</tt></pre><h2> <a name="Heading20">Overloading the Subscripts Operator</a></h2><p>For various classes that contain arrays of elements, it's handy to overload   the subscript operator to access a single element. Remember always to define   two versions of the subscript operator: a <tt>const</tt> version and a non-<tt>const</tt>   version. For example</p><pre><tt>class Ptr_collection</tt><tt>{</tt><tt>private :</tt><tt> void **ptr_array;</tt><tt> int elements;</tt><tt>public: </tt><tt>  Ptr_collection() {}</tt><tt>  //...</tt><tt>  void * operator [] (int index) { return ptr_array[index];}</tt><tt>  const void * operator [] (int index) const { return ptr_array[index];}</tt><tt>};</tt><tt>void f(const Ptr_collection &amp; pointers)</tt><tt>{</tt><tt>  const void *p = pointers[0]; //calls const version of operator [] </tt><tt>  if ( p == 0) </tt><tt>    return;</tt><tt>  else</tt><tt>  {</tt><tt>    //...use p </tt><tt>  }</tt><tt>}</tt></pre><h2> <a name="Heading21">Function Objects</a></h2><p>A function object is implemented as a class that contains an overloaded version   of the function call operator. An instance of such a class can be used just   like a function. Ordinary functions can have any number of arguments; therefore,   operator <tt>()</tt> is exceptional among other operators because it can have   an arbitrary number of parameters. In addition, it can have default arguments.   In the following example, a function object implements a generic increment function:</p><pre><tt> #include &lt;iostream&gt;</tt><tt>using namespace std;</tt><tt>class increment</tt><tt>{</tt><tt>  //a generic increment function</tt><tt>  public : template &lt; class T &gt; T operator()  (T t) const { return ++t;}</tt><tt>};</tt><tt>void f(int n, const increment&amp; incr)</tt><tt>{ </tt><tt>  cout &lt;&lt; incr(n); //output 1</tt><tt>}</tt><tt>int  main()</tt><tt>{</tt><tt>  int i = 0;</tt><tt>  increment incr;</tt><tt>  f(i, incr);</tt><tt>  return 0;</tt><tt>}</tt></pre><h2> <a name="Heading22">Conclusions</a></h2><p>The concept of operator overloading is neither new nor C++ exclusive. It is   one of the most fundamental facilities for implementing abstract data types   and compound classes. In many ways, overloaded operators in C++ behave like   ordinary member functions: They are inherited, they can be overloaded more than   once, and they can be declared as either nonstatic members or as nonmember functions.   However, several restrictions apply to overloaded operators. An overloaded operator   has a fixed number of parameters, and it cannot have default arguments. In addition,   the associativity and the precedence of an operator cannot be altered. Built-in   operators have an interface, consisting of the number of operands to which the   operator can be applied, whether the operator modifies any of its operands,   and result that is returned by the operator. When you are overloading an operator,   it is recommended that you conform to its built-in interface.</p><p>Conversion operators are a special type of overloaded operators. They differ   from ordinary overloaded operators in two respects: They do not have a return   value and they do not take any arguments. </p><p>&nbsp;</p><CENTER><P><HR>  <A HREF="/publishers/que/series/professional/0789720221/index.htm"><img src="/publishers/que/series/professional/0789720221/button/contents.gif" WIDTH="128"HEIGHT="28" ALIGN="BOTTOM" ALT="Contents" BORDER="0"></A> <BR><BR><BR><p></P><P>&#169; <A HREF="/publishers/que/series/professional/0789720221/copy.htm">Copyright 1999</A>, Macmillan Computer Publishing. Allrights reserved.</p></CENTER></BODY></HTML>

⌨️ 快捷键说明

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