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

📄 ch03.htm

📁 c++语言操作手册
💻 HTM
📖 第 1 页 / 共 3 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"><HTML><HEAD>	<META NAME="Author" Content="Steph Mineart">	<META HTTP-EQUIV="Content-Type" CONTENT="text/html;CHARSET=iso-8859-1">	<TITLE>ANSI/ISO C++ Professional Programmer's Handbook - Chapter 3 - Operator Overloading </TITLE>	<link rel="stylesheet"  TYPE="text/css" href="/includes/stylesheets/ebooks.css"></head><BODY TEXT="#000000" BGCOLOR="#FFFFFF"><CENTER><H1><img src="/publishers/que/series/professional/0789720221/button/que.gif" WIDTH="171" HEIGHT="66" ALIGN="BOTTOM" BORDER="0"><BR>ANSI/ISO C++ Professional Programmer's Handbook</H1></CENTER><CENTER>  <P><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>   <HR></CENTER><H1 align="center"> 3</H1><h1 align="center"> Operator Overloading</h1><address>by Danny Kalev</address><ul>  <li><a href="#Heading1">Introduction</a>   <li><a href="#Heading2">Operator Overloading Rules of Thumb</a>     <ul>      <li><a href="#Heading3">Members and Nonmembers</a>       <li><a href="#Heading4">Operator's Interface</a>       <li><a href="#Heading5"> Operator Associativity</a>     </ul>  <li><a href="#Heading6">Restrictions on Operator Overloading</a>     <ul>      <li><a href="#Heading7">Operators Can Only Be Overloaded for User-Defined         Types </a>       <li><a href="#Heading8">Invention of New Operators Is Not Allowed</a>       <li><a href="#Heading9"> Precedence and Argument Number</a>       <li><a href="#Heading10">Default Parameters</a>       <li><a href="#Heading11">Operators That Cannot Be Overloaded</a>     </ul>  <li><a href="#Heading12">Conversion Operators</a>     <ul>      <li><a href="#Heading13">Standard Versus User-Defined Conversions</a>     </ul>  <li><a href="#Heading14">Postfix and Prefix Operators</a>   <li><a href="#Heading15">Using Function Call Syntax</a>   <li><a href="#Heading16">Consistent Operator Overloading</a>   <li><a href="#Heading17"> 'Returning Objects by Value</a>   <li><a href="#Heading18">Multiple Overloading</a>   <li><a href="#Heading19">Overloading Operators for Other User-Defined types</a>   <li><a href="#Heading20">Overloading the Subscripts Operator</a>   <li><a href="#Heading21">Function Objects</a>   <li><a href="#Heading22">Conclusions</a> </ul><hr size=4><h2> <a name="Heading1">Introduction</a></h2><p>A built-in operator can be extended to support user-defined types as well.   Such an extension <i>overloads</i> the predefined meaning of an operator rather   than overrides it. Although ordinary functions can offer the same functionality,   operator overloading provides a uniform notational convention that is clearer   than the ordinary function call syntax. For example</p><pre><tt>Monday &lt; Tuesday; //overloaded &lt; </tt><tt>Greater_than(Monday, Tuesday); </tt></pre><p>The history of operator overloading can be traced back to the early days of   Fortran. Fortran, the first high-level programming language, presented the concept   of operator overloading in a way that was revolutionary back in the mid-1950s.   For the first time, built-in operators such as <tt>+</tt> or <tt>-</tt> could   be applied to various data types: integers, real and complex. Until then, assembly   languages -- which didn't even support operator notation -- had been the only   choice for programmers. Fortran's operator overloading was limited to a fixed   set of built-in data types; they could not be extended by the programmer. Object-based   programming languages offered user-defined overloaded operators. In such languages,   it is possible to associate a set of operators with a user-defined type. Object-oriented   languages usually incorporate operator overloading as well.</p><p>The capability to redefine the meaning of a built-in operator in C++ was a   source of criticism. People -- mostly C programmers making the migration to   C++ -- felt that overloading an operator was as dangerous as enabling the programmer   to add, remove, or change keywords of the language. Still, notwithstanding the   potential Tower of Babel that might arise as a result, operator overloading   is one of the most fundamental features of C++ and is mandatory for generic   programming (generic programming is discussed in Chapter 10, "STL and Generic   Programming."). Today, even languages that tried to make do without operator   overloading are in the process of adding this feature.</p><p>This chapter explores the benefits as well as the potential problems of operator   overloading. It also discusses the few restrictions that apply to operator overloading.   Finally, it presents conversion operators, which are a special form of overloaded   operators.</p><p>An overloaded operator is essentially a function whose name is an operator   preceded by the keyword <tt>operator</tt>. For example</p><pre><tt>class Book</tt><tt>{</tt><tt>private:</tt><tt>  long ISBN;</tt><tt>public:</tt><tt>//...</tt><tt>  long get_ISBN() const { return ISBN;}</tt><tt>};</tt><tt>bool operator &lt; (const Book&amp; b1, const Book&amp; b2) // overload operator &lt;</tt><tt>{</tt><tt>  return b1.get_ISBN() &lt; b2.get_ISBN();</tt><tt>} </tt></pre><h2> <a name="Heading2">Operator Overloading Rules of Thumb</a></h2><p>C++ enforces few restrictions on operator overloading. For instance, it does   not prohibit a programmer from overloading the operator <tt>++</tt> in order   to perform a decrement operation on its object (to the dismay of its users,   who would instead expect operator <tt>++</tt> to perform an increment operation).   Such misuses and puns can lead to a cryptic coding style that is almost unintelligible.   Often, the source code that contains the definition of an overloaded operator   is not accessible to its users; therefore, overloading an operator in an unexpected,   nonintuitive manner is not recommended.</p><p>The other extreme, avoiding operator overloading altogether, is not a practical   choice either because it means giving up an important tool for data abstraction   and generic programming. When you are overloading an operator to support a user-defined   type, therefore, it is recommended that you adhere to the basic semantics of   the corresponding built-in operator. In other words, an overloaded operator   has the same side effects on its operands and manifests the same interface as   does the corresponding built-in operator.</p><h3> <a name="Heading3">Members and Nonmembers</a></h3><p>Most of the overloaded operators can be declared either as nonstatic class   members or as nonmember functions. In the following example, the operator <tt>==</tt>   is overloaded as a nonstatic class member:</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>  bool operator == (const Date &amp; d ); // 1: member function</tt><tt>};</tt></pre><p>Alternatively, it can be declared as a <tt>friend</tt> function (the criteria   for choosing between a member and a friend will be discussed later in this chapter):</p><pre><tt>bool operator ==( const Date &amp; d1, const Date&amp; d2); // 2: nonmember function</tt><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>  friend bool operator ==( const Date &amp; d1, const Date&amp; d2);</tt><tt>};</tt></pre><p>Nonetheless, the operators <tt>[]</tt>, <tt>()</tt>, <tt>=</tt>, and <tt>-&gt;</tt>   can only be declared as nonstatic member functions; this ensures that their   first operand is an lvalue.</p><h3> <a name="Heading4">Operator's Interface</a></h3><p>When you overload an operator, adhere to the interface of its built-in counterpart.   The interface of an operator consists of the number of operands to which it   applies, whether any of these operands can be altered by the operator, and the   result that is returned by the operator. For example, consider operator <tt>==</tt>.   Its built-in version can be applied to a wide variety of fundamental types,   including <tt>int</tt>, <tt>bool</tt>, <tt>float</tt>, and <tt>char</tt>, and   to pointers. The underlying computation process that is required for testing   whether the operands of operator <tt>==</tt> are equal is an implementation-detail.   However, it can be generalized that the built-in <tt>==</tt> operator tests   its left and right operands for equality and returns a <tt>bool</tt> value as   its result. It is important to note also that operator <tt>==</tt> does not   modify any of its operands; in addition, the order of the operands is immaterial   in the case of operator <tt>==</tt>. An overloaded operator <tt>==</tt> should   conform to this behavior, too.</p><h3> <a name="Heading5"> Operator Associativity</a></h3><p>Operator <tt>==</tt> is binary and symmetrical. An overloaded version of <tt>==</tt>   conforms to these qualities. It takes two operands, which are of the same type.   Indeed, one can use operator <tt>==</tt> to test the equality of two operands   of distinct fundamental types, for example <tt>char</tt> and <tt>int</tt>. However,   C++ automatically applies <i>integral promotion</i> to the operands in this   case; as a result, the seemingly distinct types are promoted to a single common   type before they are compared.<i> </i>The symmetrical quality implies that an   overloaded operator <tt>==</tt> is to be defined as a <tt>friend</tt> function   rather than a member function. So that you can see why, here's a comparison   of two different versions of the same overloaded operator <tt>==</tt>:</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();</tt><tt>  bool  operator == (const Date &amp; d) const;  // 1 asymmetrical</tt><tt>  friend bool operator ==(const Date&amp; d1, const Date&amp; d2); //2 symmetrical</tt><tt>};</tt><tt>bool operator ==(const Date&amp; d1, const Date&amp; d2);</tt></pre><p>The overloaded operator <tt>==</tt> that is declared as a member function in   <tt>(1)</tt> is inconsistent with the built-in operator <tt>==</tt> because   it takes two arguments of different types. The compiler transforms the member   operator <tt>==</tt> into the following:</p><pre><tt>bool  Date::operator == (const Date *const,  const Date&amp;) const; </tt></pre><p>The first argument is a <tt>const this</tt> pointer that points to a <tt>const</tt>   object (remember that <tt>this</tt> is always a <tt>const</tt> pointer; it points   to a <tt>const</tt> object when the member function is also <tt>const)</tt>.   The second argument is a reference to <tt>const Date</tt>. Clearly, these are   two distinct types for which no standard conversion exists. On the other hand,   the <tt>friend</tt> version takes two arguments of the same type. There are   practical implications to favoring the <tt>friend</tt> version over the member   function. STL algorithms rely on a symmetrical version of the overloaded operator   <tt>==</tt>. For example, containers that store objects that do not have symmetrical   operator <tt>==</tt> cannot be sorted.</p><p>Another example, built-in operator <tt>+=</tt>, which also takes two operands,   modifies its left operand but leaves the right operand unchanged. The interface   of an overloaded <tt>+=</tt> needs to reflect the fact that it modifies its   object but not its right operand. This is reflected by the declaration of the   function parameter as <tt>const</tt>, whereas the function itself is a non-<tt>const</tt>   member function. For example</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();</tt><tt>  //built-in += changes its left operand but not its right one</tt><tt>  //the same behavior is maintained here</tt><tt>  Date &amp; operator += (const Date &amp; d);</tt><tt>};</tt></pre><p>To conclude, it can be said that every overloaded operator must implement an   interface that is similar to the one that is manifested by the built-in operator.   The implementer is free to define the underlying operation and hide its details   -- as long as it conforms to the interface.</p><h2> <a name="Heading6">Restrictions on Operator Overloading</a></h2><p>As was previously noted, an overloaded operator is a function that is declared   with the <tt>operator</tt> keyword, immediately followed by an <i>operator id.</i>   An operator id can be one of the following:</p><pre><tt>new  delete    new[]     delete[]</tt><tt>+    -    *    /    %    ^    &amp;    |    ~</tt><tt>!    =    &lt;    &gt;    +=   -=   *=   /=   %=</tt><tt>^=   &amp;=   |=   &lt;&lt;   &gt;&gt;   &gt;&gt;=  &lt;&lt;=  ==   !=</tt><tt>&lt;=   &gt;=   &amp;&amp;   ||   ++   --   ,    -&gt;*  -&gt;</tt><tt>()   []</tt></pre><p>In addition, the following operators can be overloaded both in their unary   and binary forms:</p><pre><tt>+    -    *     &amp;</tt></pre><p>Overloaded operators are inherited in the same manner as other base class functions. 

⌨️ 快捷键说明

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