📄 chapter12.html
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<!--
This document was converted from RTF source:
By rtftohtml 4.19
See http://www.sunpack.com/RTF
Filename:TIC2Vone.rtf
Application Directory:C:\TOOLS\RTF2HTML\
Subject:
Author:Bruce Eckel
Operator:Bruce Eckel
Document Comments:
Version Comments:
Comments:
Keywords:
Translation Date:09/27/2001
Translation Time:05:25:46
Translation Platform:Win32
Number of Output files:22
This File:Chapter12.html
SplitDepth=1
SkipNavPanel=1
SkipLeadingToc=1
SkipTrailingToc=1
GenContents=1
GenFrames=1
GenIndex=1
-->
<HEAD lang="en"><META http-equiv="Content-Type" content="text/html">
<TITLE>12: Operator Overloading</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF"><DIV ALIGN="CENTER">
<a href="http://www.MindView.net">
<img src="mindview-head.gif" alt="MindView Inc." BORDER = "0"></a>
<CENTER>
<FONT FACE="Verdana" size = "-1">
[ <a href="README-HTML.txt">Viewing Hints</a> ]
[ <a href="http://www.mindview.net/CPPServices/SolutionGuide.html">Exercise Solutions</a> ]
[ <a href="http://www.mindview.net/ThinkingInCPP2e.html">Volume 2</a> ]
[ <a href="http://www.mindview.net/MailingList.html">Free Newsletter</a> ] <br>
[ <a href="http://www.mindview.net/CPPServices/#PublicSeminars">Seminars</a> ]
[ <a href="http://www.mindview.net/CPPServices/#SeminarsOnCD">Seminars on CD ROM</a> ]
[ <a href="http://www.mindview.net/CPPServices/#ConsultingServices">Consulting</a> ]
</FONT>
<H2><FONT FACE="Verdana">
Thinking in C++, 2nd ed. Volume 1</FONT></H2></FONT>
<H3><FONT FACE="Verdana">©2000 by Bruce Eckel</FONT></H3></FONT>
<FONT FACE="Verdana" size = "-1">
[ <a href="Chapter11.html">Previous Chapter</a> ]
[ <a href="Contents.html">Table of Contents</a> ]
[ <a href="DocIndex.html">Index</a> ]
[ <a href="Chapter13.html">Next Chapter</a> ]
</FONT>
</CENTER>
</P></DIV><A NAME="_Toc472654946"></A><FONT FACE = "Verdana"><H1 ALIGN="LEFT">
12:
<A NAME="_Toc305593233"></A><A NAME="_Toc305628705"></A><A NAME="_Toc312373971"></A>Operator
Overloading</H1></FONT>
<A NAME="Heading348"></A><FONT FACE = "Verdana"><H1 ALIGN="LEFT">
</H1></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Verdana" SIZE=4>Operator overloading
<A NAME="Index1962"></A>is just “syntactic
sugar<A NAME="Index1963"></A><A NAME="Index1964"></A>,” which means it is
simply another way for you to make a function call.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The difference is that the arguments for
this function don’t appear inside parentheses, but instead they surround
or are next to characters you’ve always thought of as immutable
operators.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">There are two differences between the use
of an operator and an ordinary function call. The syntax is different; an
operator is often “called” by placing it between or sometimes after
the arguments. The second difference is that the compiler determines which
“function” to call. For instance, if you are using the operator
<B>+</B> with floating-point arguments, the compiler “calls” the
function to perform floating-point addition (this “call” is
typically the act of inserting in-line code, or a floating-point-processor
instruction). If you use operator <B>+</B> with a floating-point number and an
integer, the compiler “calls” a special function to turn the
<B>int</B> into a <B>float</B>, and then “calls” the floating-point
addition code.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">But in C++, it’s possible to define
new operators that work with classes. This definition is just like an ordinary
function definition except that the name of the function consists of the keyword
<B>operator</B> <A NAME="Index1965"></A>followed by the operator. That’s
the only difference, and it becomes a function <A NAME="Index1966"></A>like any
other function, which the compiler calls when it sees the appropriate
pattern.</FONT><A NAME="_Toc305593234"></A><A NAME="_Toc305628706"></A><A NAME="_Toc312373972"></A><A NAME="_Toc472654947"></A><BR></P></DIV>
<A NAME="Heading349"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Warning & reassurance</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">It’s tempting to become
overenthusiastic with operator overloading. It’s a fun toy, at first. But
remember it’s <I>only</I> syntactic sugar, another way of calling a
function. Looking at it this way, you have no reason to overload an operator
except if it will make the code involving your class easier to write and
especially easier to <I>read</I>. (Remember, code is read much more than it is
written.) If this isn’t the case, don’t bother.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Another common response to operator
overloading is panic; suddenly, C operators have no familiar meaning anymore.
“Everything’s changed and all my C code will do different
things!” This isn’t true. All the operators used in expressions that
contain only built-in data types cannot be changed. You can never overload
operators such that</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>1 << 4;</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">behaves differently, or</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>1.414 << 2;</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">has meaning. Only an expression
containing a user-defined type can have an overloaded
operator.</FONT><A NAME="_Toc305593235"></A><A NAME="_Toc305628707"></A><A NAME="_Toc312373973"></A><A NAME="_Toc472654948"></A><BR></P></DIV>
<A NAME="Heading350"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Syntax</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Defining an overloaded
<A NAME="Index1967"></A>operator is like defining a function, but the name of
that function is <B>operator@</B>, in which <B>@</B> represents the operator
that’s being overloaded. The number of arguments in the overloaded
operator’s argument list depends on two
factors<A NAME="Index1968"></A><A NAME="Index1969"></A><A NAME="Index1970"></A><A NAME="Index1971"></A><A NAME="Index1972"></A><A NAME="Index1973"></A><A NAME="Index1974"></A><A NAME="Index1975"></A><A NAME="Index1976"></A>:</FONT><BR></P></DIV>
<OL>
<LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Whether it’s a unary
operator (one argument) or a binary operator (two
arguments).</FONT><LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Whether
the operator is defined as a global function (one argument for unary, two for
binary) or a member function (zero arguments for unary, one for binary –
the object becomes the left-hand
argument).</FONT></OL><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here’s a
small class that shows the syntax for operator overloading:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C12:OperatorOverloadingSyntax.cpp</font>
#include <iostream>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#0000ff>class</font> Integer {
<font color=#0000ff>int</font> i;
<font color=#0000ff>public</font>:
Integer(<font color=#0000ff>int</font> ii) : i(ii) {}
<font color=#0000ff>const</font> Integer
<font color=#0000ff>operator</font>+(<font color=#0000ff>const</font> Integer& rv) <font color=#0000ff>const</font> {
cout << <font color=#004488>"operator+"</font> << endl;
<font color=#0000ff>return</font> Integer(i + rv.i);
}
Integer&
<font color=#0000ff>operator</font>+=(<font color=#0000ff>const</font> Integer& rv) {
cout << <font color=#004488>"operator+="</font> << endl;
i += rv.i;
<font color=#0000ff>return</font> *<font color=#0000ff>this</font>;
}
};
<font color=#0000ff>int</font> main() {
cout << <font color=#004488>"built-in types:"</font> << endl;
<font color=#0000ff>int</font> i = 1, j = 2, k = 3;
k += i + j;
cout << <font color=#004488>"user-defined types:"</font> << endl;
Integer ii(1), jj(2), kk(3);
kk += ii + jj;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The two overloaded operators are defined
as inline member functions that announce when they are called. The single
argument is what appears on the right-hand side of the operator for binary
operators. Unary operators have no arguments when defined as member functions.
The member function is called for the object on the left-hand side of the
operator.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">For non-conditional operators
(conditionals usually return a Boolean value), you’ll almost always want
to return <A NAME="Index1977"></A><A NAME="Index1978"></A>an object or reference
of the same type you’re operating on if the two arguments are the same
type. (If they’re not the same type, the interpretation of what it should
produce is up to you.) This way,
<A NAME="Index1979"></A><A NAME="Index1980"></A><A NAME="Index1981"></A>complicated
expressions can be built up:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>kk += ii + jj;</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>operator+</B> produces a new
<B>Integer</B> (a temporary) that is used as the <B>rv</B> argument for the
<B>operator+=</B>. This temporary is destroyed as soon as it is no longer
needed.</FONT><A NAME="_Toc305593236"></A><A NAME="_Toc305628708"></A><A NAME="_Toc312373974"></A><A NAME="_Toc472654949"></A><BR></P></DIV>
<A NAME="Heading351"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Overloadable operators</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Although you can overload
<A NAME="Index1982"></A><A NAME="Index1983"></A>almost all the operators
available in C, the use of operator overloading is fairly restrictive. In
particular, you cannot combine operators that currently have no meaning in C
(such as <B>**</B> to represent exponentiation), you cannot change the
evaluation precedence of operators, and you cannot change the number of
arguments required by an operator. This makes sense – all of these actions
would produce operators that confuse meaning rather than clarify
it.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The next two subsections give examples of
all the “regular” operators, overloaded in the form that
you’ll most likely
use.</FONT><A NAME="_Toc312373975"></A><A NAME="_Toc472654950"></A><BR></P></DIV>
<A NAME="Heading352"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Unary operators</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The following example shows the syntax to
overload all the unary
operators<A NAME="Index1984"></A><A NAME="Index1985"></A>, in the form of both
global functions (non-member <B>friend </B>functions) and as member functions.
These will expand upon the <B>Integer </B>class shown previously and add a new
<B>byte </B>class. The meaning of your particular operators will depend on the
way you want to use them, but consider the client programmer before doing
something unexpected.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here is a catalog of all the unary
functions:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C12:OverloadingUnaryOperators.cpp</font>
#include <iostream>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#009900>// Non-member functions:</font>
<font color=#0000ff>class</font> Integer {
<font color=#0000ff>long</font> i;
Integer* This() { <font color=#0000ff>return</font> <font color=#0000ff>this</font>; }
<font color=#0000ff>public</font>:
Integer(<font color=#0000ff>long</font> ll = 0) : i(ll) {}
<font color=#009900>// No side effects takes const& argument:</font>
<font color=#0000ff>friend</font> <font color=#0000ff>const</font> Integer&
<font color=#0000ff>operator</font>+(<font color=#0000ff>const</font> Integer& a);
<font color=#0000ff>friend</font> <font color=#0000ff>const</font> Integer
<font color=#0000ff>operator</font>-(<font color=#0000ff>const</font> Integer& a);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -