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

📄 index.html

📁 C程序员手册(英文)
💻 HTML
📖 第 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 + -