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

📄 ei19.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN" "http://www.w3.org/TR/REC-html40/frameset.dtd">
<HTML LANG="EN">
<HEAD>
<title>Effective C++, 2E | Item 19: Differentiate among member functions, non-member functions, and friend functions</TITLE>
<LINK REL=STYLESHEET HREF=../INTRO/ECMEC.CSS>

<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/COOKIE.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">var imagemax = 0; setCurrentMax(0);</SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/DINGBATS.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">
var dingbase = "EI19_DIR.HTM";
var dingtext = "Item E19, P";
if (self == top) {
 top.location.replace(dingbase + this.location.hash);
}
</SCRIPT>

</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" ONLOAD="setResize()">
<!-- SectionName="E19: Member funcs, non-member funcs, friends" -->
<A NAME="5887"></A>
<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./EI18_FR.HTM" TARGET="_top">Item 18: Strive for class interfaces that are complete and minimal.</A> &nbsp;&nbsp;<BR>&nbsp;&nbsp;Continue to <A HREF="./EI20_FR.HTM" TARGET="_top">Item 20: Differentiate among member functions, non-member functions, and friend functions.</A></FONT></DIV>

<P><A NAME="dingp1"></A><A NAME="p84"></A><FONT ID="eititle">Item 19: &nbsp;Differentiate among member functions, non-member functions, and friend functions.</FONT><SCRIPT>create_link(1);</SCRIPT>

</P>

<A NAME="5889"></A>
<P><A NAME="dingp2"></A>
The biggest difference between member functions and non-member functions is that member functions can be virtual and non-member functions can't. As a result, if you have a function that has to be dynamically bound (see <A HREF="./EI38_FR.HTM#177948" TARGET="_top">Item 38</A>), you've got to use a virtual function, and that virtual function must be a member of some class. It's as simple as that. If your function doesn't need to be virtual, however, the water begins to muddy a <NOBR>bit.<SCRIPT>create_link(2);</SCRIPT>

</NOBR></P>
<A NAME="5893"></A>
<P><A NAME="dingp3"></A>
Consider a class for representing rational numbers:<SCRIPT>create_link(3);</SCRIPT>

<A NAME="5895"></A>
<UL><PRE>class Rational {
public:
  Rational(int numerator = 0, int denominator = 1);
  int numerator() const;
  int denominator() const;
</PRE>
</UL><A NAME="16284"></A>
<UL><PRE>private:
  ...
};
</PRE>
</UL></P>
<A NAME="5900"></A>
<P><A NAME="dingp4"></A>
As it stands now, this is a pretty useless class. (Using the terms of <A HREF="./EI18_FR.HTM#17774" TARGET="_top">Item 18</A>, the interface is certainly minimal, but it's <I>far</I> from complete.) You know you'd like to support arithmetic operations like addition, subtraction, multiplication, etc., but you're unsure whether you should implement them via a member function, a non-member function, or possibly a non-member function that's a <NOBR>friend.<SCRIPT>create_link(4);</SCRIPT>

</NOBR></P>
<A NAME="5902"></A>
<P><A NAME="dingp5"></A>
When in doubt, be object-oriented. You know that, say, multiplication of rational numbers is related to the <CODE>Rational</CODE> class, so try bundling the operation with the class by making it a member <NOBR>function:<SCRIPT>create_link(5);</SCRIPT>

</NOBR></P>
<A NAME="5903"></A>
<UL><PRE>class Rational {
public:
</PRE>
</UL><A NAME="5904"></A>
<UL><PRE>  ...
</PRE>
</UL><A NAME="5905"></A>
<UL><PRE>  const Rational operator*(const Rational&amp; rhs) const;
};
</PRE>
</UL><A NAME="5906"></A>
<P><A NAME="dingp6"></A>
(If you're unsure why this function is declared the way it is &#151; returning a <CODE>const</CODE> by-value result, but taking a reference-to-<CODE>const</CODE> as its argument &#151; consult Items <A HREF="./EI21_FR.HTM#6003" TARGET="_top">21</A>-<A HREF="./EI23_FR.HTM#6210" TARGET="_top">23</A>.)<SCRIPT>create_link(6);</SCRIPT>

</P>
<A NAME="5913"></A>
<P><A NAME="dingp7"></A>
Now you can multiply rational numbers with the greatest of <NOBR>ease:<SCRIPT>create_link(7);</SCRIPT>

</NOBR></P>
<A NAME="5914"></A>
<UL><PRE>Rational oneEighth(1, 8);
Rational oneHalf(1, 2);
</PRE>
</UL><A NAME="5915"></A>
<UL><PRE>Rational result = oneHalf * oneEighth;      // fine
</PRE>
</UL><A NAME="5916"></A>
<UL><PRE>result = result * oneEighth;                // fine
</PRE>
</UL><A NAME="5917"></A>
<P><A NAME="dingp8"></A>
<A NAME="p85"></A>But you're not satisfied. You'd also like to support mixed-mode operations, where <CODE>Rational</CODE>s can be multiplied with, for example, <CODE>int</CODE>s. When you try to do this, however, you find that it works only half the <NOBR>time:<SCRIPT>create_link(8);</SCRIPT>

</NOBR></P>
<A NAME="5918"></A>
<UL><PRE>result = oneHalf * 2;      // fine
</PRE>
</UL><A NAME="5919"></A>
<UL><PRE>result = 2 * oneHalf;      // error!
</PRE>
</UL><A NAME="5920"></A>
<P><A NAME="dingp9"></A>
This is a bad omen. Multiplication is supposed to be commutative, <NOBR>remember?<SCRIPT>create_link(9);</SCRIPT>

</NOBR></P>
<A NAME="5921"></A>
<P><A NAME="dingp10"></A>
The source of the problem becomes apparent when you rewrite the last two examples in their equivalent functional <NOBR>form:<SCRIPT>create_link(10);</SCRIPT>

</NOBR></P>
<A NAME="5922"></A>
<UL><PRE>result = oneHalf.operator*(2);      // fine
</PRE>
</UL><A NAME="5923"></A>
<UL><PRE>result = 2.operator*(oneHalf);      // error!
</PRE>
</UL><A NAME="5924"></A>
<P><A NAME="dingp11"></A>
The object <CODE>oneHalf</CODE> is an instance of a class that contains an <CODE>operator*</CODE>, so your compilers call that function. However, the integer 2 has no associated class, hence no <CODE>operator*</CODE> member function. Your compilers will also look for a non-member <CODE>operator*</CODE> (i.e., one that's in a visible namespace or is global) that can be called like <NOBR>this,<SCRIPT>create_link(11);</SCRIPT>

</NOBR></P>
<A NAME="5925"></A>
<UL><PRE>result = operator*(2, oneHalf);      // error!
</PRE>
</UL><A NAME="5926"></A>
<P><A NAME="dingp12"></A>
but there is no non-member <CODE>operator*</CODE> taking an <CODE>int</CODE> and a <CODE>Rational</CODE>, so the search <NOBR>fails.<SCRIPT>create_link(12);</SCRIPT>

</NOBR></P>
<A NAME="5927"></A>
<P><A NAME="dingp13"></A>
Look again at the call that succeeds. You'll see that its second parameter is the integer 2, yet <CODE>Rational::operator*</CODE> takes a <CODE>Rational</CODE> object as its argument. What's going on here? Why does 2 work in one position and not in the <NOBR>other?<SCRIPT>create_link(13);</SCRIPT>

</NOBR></P>
<A NAME="5930"></A>
<P><A NAME="dingp14"></A>
What's going on is implicit type conversion. Your compilers know you're passing an <CODE>int</CODE> and the function requires a <CODE>Rational</CODE>, but they also know that they can conjure up a suitable <CODE>Rational</CODE> by calling the <CODE>Rational</CODE> constructor with the <CODE>int</CODE> you provided, so that's what they do (see <A HREF="../MEC/MI19_FR.HTM#41177" TARGET="_top">Item M19</A>). In other words, they treat the call as if it had been written more or less like <NOBR>this:<SCRIPT>create_link(14);</SCRIPT>

</NOBR></P>
<A NAME="5931"></A>
<UL><PRE>
const Rational temp(2);      // create a temporary
                             // Rational object from 2
</PRE>
</UL><A NAME="5932"></A>
<UL><PRE>
result = oneHalf * temp;     // same as
                             // oneHalf.operator*(temp);
</PRE>
</UL><A NAME="76965"></A>
<P><A NAME="dingp15"></A>
Of course, they do this only when non-<CODE>explicit</CODE> constructors are involved, because <CODE>explicit</CODE> constructors can't be used for implicit conversions; that's what <CODE>explicit</CODE> means. If <CODE>Rational</CODE> were defined like <NOBR>this,<SCRIPT>create_link(15);</SCRIPT>

</NOBR></P>
<A NAME="76967"></A>
<UL><PRE><A NAME="p86"></A>class Rational {
public:
  explicit Rational(int numerator = 0,     // this ctor is
                    int denominator = 1);  // now <I>explicit</I>
  ...
</PRE>
</UL><A NAME="76958"></A>
<UL><PRE>  const Rational operator*(const Rational&amp; rhs) const;
</PRE>
</UL><A NAME="76960"></A>
<UL><PRE>  ...
</PRE>
</UL><A NAME="76959"></A>
<UL><PRE>};
</PRE>
</UL><A NAME="76939"></A>
<P><A NAME="dingp16"></A>
<I>neither</I> of these statements would <NOBR>compile:<SCRIPT>create_link(16);</SCRIPT>

</NOBR></P>

⌨️ 快捷键说明

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