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

📄 c++ faq lite[13]--算符重载(新).htm

📁 c++faq。里面有很多关于c++的问题的解答。
💻 HTM
📖 第 1 页 / 共 4 页
字号:
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/friends.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=[13.7]></A>
<DIV class=FaqTitle>
<H3>[13.7] 我能为“幂”运算创建一个 <TT><FONT face=新宋体>operator**</FONT></TT> 吗?</H3></DIV>
<P>不行。 
<P>运算符的名称、优先级、结合性以及元数都是由语言固定的。在C++中没有<TT><FONT 
face=新宋体>operator**</FONT></TT>,因此你不能为类类型创建它。 
<P>如果还有疑问,考虑一下<TT><FONT face=新宋体>x&nbsp;**&nbsp;y</FONT></TT>与<TT><FONT 
face=新宋体>x&nbsp;*&nbsp;(*y)</FONT></TT>等同(换句话说,编译器假定 <TT><FONT face=新宋体>y 
</FONT></TT>是一个指针)。此外,算符重载只不过是函数调用的语法修饰。虽然这种特殊的语法修饰非常美妙,但它没有增加任何本质的东西。我建议你重载<TT><FONT 
face=新宋体>pow(base,exponent)</FONT></TT>(双精度版本在<TT><FONT 
face=新宋体>&lt;cmath&gt;</FONT></TT>中)。 
<P>顺便提一下,<TT><FONT face=新宋体>operator^</FONT></TT>可以成为幂运算,只是优先级和结合性是错误的。 
<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/operator-overloading.html#top">Top</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/operator-overloading.html#bottom">Bottom</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/assignment-operators.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/friends.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=[13.8]></A>
<DIV class=FaqTitle>
<H3>[13.8] 如何为<FONT face=新宋体><TT>Matrix</TT><TT>(</TT></FONT>矩阵)类创建下标运算符? <IMG 
alt=UPDATED! 
src="C++ FAQ Lite[13]--算符重载(新).files/updated.gif"></H3></DIV><SMALL><EM>[Recently 
changed so it uses new-style headers and the <TT><FONT 
face=新宋体>std::</FONT></TT> syntax (on 7/00). <A 
href="http://www.sunistudio.com/cppfaq/operator-overloading.html#[13.10]">Click 
here to go to the next FAQ in the "chain" of recent changes<!--rawtext:[13.10]:rawtext--></A>.]</EM></SMALL> 
<P>用 <TT><FONT face=新宋体>operator()</FONT></TT>而不是<TT><FONT 
face=新宋体>operator[]</FONT></TT>。 
<P>当有多个下标时,最清晰的方式是使用<TT><FONT face=新宋体>operator()</FONT></TT>而不是<TT><FONT 
face=新宋体>operator[]</FONT></TT>。原因是<TT><FONT 
face=新宋体>operator[]</FONT></TT>总是带一个参数,而<TT><FONT 
face=新宋体>operator()</FONT></TT>可以带任何数目的参数(在矩形的矩阵情况下,需要两个参数)。 
<P>如: 
<P>
<DIV class=CodeBlock><TT><FONT 
face=新宋体>&nbsp;class&nbsp;Matrix&nbsp;{<BR>&nbsp;public:<BR>&nbsp;&nbsp;&nbsp;Matrix(unsigned&nbsp;rows,&nbsp;unsigned&nbsp;cols);<BR>&nbsp;&nbsp;&nbsp;double&amp;&nbsp;operator()&nbsp;(unsigned&nbsp;row,&nbsp;unsigned&nbsp;col);<BR>&nbsp;&nbsp;&nbsp;double&nbsp;&nbsp;operator()&nbsp;(unsigned&nbsp;row,&nbsp;unsigned&nbsp;col)&nbsp;const;<BR>&nbsp;&nbsp;&nbsp;</FONT></TT><EM>//&nbsp;...</EM><TT><BR><FONT 
face=新宋体>&nbsp;&nbsp;~Matrix();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></TT><EM>//&nbsp;析构函数</EM><TT><BR><FONT 
face=新宋体>&nbsp;&nbsp;&nbsp;Matrix(const&nbsp;Matrix&amp;&nbsp;m);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></TT><EM>//&nbsp;拷贝构造函数</EM><TT><BR><FONT 
face=新宋体>&nbsp;&nbsp;&nbsp;Matrix&amp;&nbsp;operator=&nbsp;(const&nbsp;Matrix&amp;&nbsp;m);&nbsp;&nbsp;&nbsp;</FONT></TT><EM>//&nbsp;赋值算符</EM><TT><BR><FONT 
face=新宋体>&nbsp;&nbsp;&nbsp;</FONT></TT><EM>//&nbsp;...</EM><TT><BR><FONT 
face=新宋体>&nbsp;private:<BR>&nbsp;&nbsp;&nbsp;unsigned&nbsp;rows_,&nbsp;cols_;<BR>&nbsp;&nbsp;&nbsp;double*&nbsp;data_;<BR>&nbsp;};<BR>&nbsp;<BR>&nbsp;inline<BR>&nbsp;Matrix::Matrix(unsigned&nbsp;rows,&nbsp;unsigned&nbsp;cols)<BR>&nbsp;&nbsp;&nbsp;:&nbsp;rows_&nbsp;(rows),<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cols_&nbsp;(cols),<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data_&nbsp;(new&nbsp;double[rows&nbsp;*&nbsp;cols])<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;if&nbsp;(rows&nbsp;==&nbsp;0&nbsp;||&nbsp;cols&nbsp;==&nbsp;0)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;BadIndex("Matrix&nbsp;constructor&nbsp;has&nbsp;0&nbsp;size");<BR>&nbsp;}<BR>&nbsp;<BR>&nbsp;inline<BR>&nbsp;Matrix::~Matrix()<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;delete[]&nbsp;data_;<BR>&nbsp;}<BR>&nbsp;<BR>&nbsp;inline<BR>&nbsp;double&amp;&nbsp;Matrix::operator()&nbsp;(unsigned&nbsp;row,&nbsp;unsigned&nbsp;col)<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;if&nbsp;(row&nbsp;&gt;=&nbsp;rows_&nbsp;||&nbsp;col&nbsp;&gt;=&nbsp;cols_)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;BadIndex("Matrix&nbsp;subscript&nbsp;out&nbsp;of&nbsp;bounds");<BR>&nbsp;&nbsp;&nbsp;return&nbsp;data_[cols_*row&nbsp;+&nbsp;col];<BR>&nbsp;}<BR>&nbsp;<BR>&nbsp;inline<BR>&nbsp;double&nbsp;Matrix::operator()&nbsp;(unsigned&nbsp;row,&nbsp;unsigned&nbsp;col)&nbsp;const<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;if&nbsp;(row&nbsp;&gt;=&nbsp;rows_&nbsp;||&nbsp;col&nbsp;&gt;=&nbsp;cols_)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;BadIndex("const&nbsp;Matrix&nbsp;subscript&nbsp;out&nbsp;of&nbsp;bounds");<BR>&nbsp;&nbsp;&nbsp;return&nbsp;data_[cols_*row&nbsp;+&nbsp;col];<BR>&nbsp;} 
</FONT></TT></DIV>
<P>然后,你可以使用<TT><FONT face=新宋体>m(i,j)</FONT></TT>来访问<TT><FONT 
face=新宋体>Matrix</FONT></TT> <TT><FONT face=新宋体>m</FONT></TT> 的元素,而不是<TT><FONT 
face=新宋体>m[i][j]:</FONT></TT> 
<P>
<DIV class=CodeBlock><TT><FONT 
face=新宋体>&nbsp;int&nbsp;main()<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;Matrix&nbsp;m(10,10);<BR>&nbsp;&nbsp;&nbsp;m(5,8)&nbsp;=&nbsp;106.15;<BR>&nbsp;&nbsp;&nbsp;std::cout&nbsp;&lt;&lt;&nbsp;m(5,8);<BR>&nbsp;&nbsp;&nbsp;</FONT></TT><EM>//&nbsp;...</EM><TT><BR><FONT 
face=新宋体>&nbsp;} </FONT></TT></DIV>
<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/operator-overloading.html#top">Top</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/operator-overloading.html#bottom">Bottom</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/assignment-operators.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/friends.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=[13.9]></A>
<DIV class=FaqTitle>
<H3>[13.9] 为什么<TT><FONT face=新宋体>Matrix</FONT></TT>(矩阵)类的接口不应该象数组的数组?</H3></DIV>
<P>本 FAQ 其实是关于:某些人建立的Matrix 类,带有一个返回 <TT><FONT face=新宋体>Array</FONT></TT> 
对象的引用的<TT><FONT face=新宋体>operator[]</FONT></TT>。而该<TT><FONT 
face=新宋体>Array</FONT></TT> 对象也带有一个 <TT><FONT face=新宋体>operator[]</FONT></TT> 
,它返回Matrix的一个元素(例如,一个<TT><FONT 
face=新宋体>double</FONT></TT>的引用)。因此,他们使用类似<TT><FONT face=新宋体>m[i][j]</FONT></TT> 
的语法来访问矩阵的元素,而不是<A 
href="http://www.sunistudio.com/cppfaq/operator-overloading.html#[13.8]">象<TT><FONT 
face=新宋体>m(i,j)</FONT></TT>的语法</A>。 
<P>数组的数组方案显然可以工作,但相对于<A 
href="http://www.sunistudio.com/cppfaq/operator-overloading.html#[13.8]"><TT><FONT 
face=新宋体>operator()</FONT></TT>方法</A>来说,缺乏灵活性。尤其是,用<TT><FONT 
face=新宋体>[][]</FONT></TT>方法很难表现的时候,用<TT><FONT 
face=新宋体>operator()</FONT></TT>方法可以很简单的完成,因此<TT><FONT 
face=新宋体>[][]</FONT></TT>方法很可能导致差劲的表现,至少某些情况细是这样的。 
<P>例如,实现<TT><FONT 
face=新宋体>[][]</FONT></TT>方法的最简单途径就是使用作为密集矩阵的,以以行为主的形式保存(或以列为主,我记不清了)的物理布局。相反,<A 
href="http://www.sunistudio.com/cppfaq/operator-overloading.html#[13.8]"><TT><FONT 
face=新宋体>operator()</FONT></TT> 方法</A>完全隐藏了矩阵的物理布局,在这种情况下,它可能带来更好的表现。 
<P>可以这么认为:<TT><FONT face=新宋体>operator()</FONT></TT>方法永远不比<TT><FONT 
face=新宋体>[][]</FONT></TT>方法差,有时更好。 
<UL>
  <LI><TT><FONT face=新宋体>operator()</FONT></TT> 永远不差,是因为用<TT><FONT 
  face=新宋体>operator()</FONT></TT>方法实现以行为主的密集矩阵的物理布局非常容易。因此,当从性能观点出发,那样的结构正好是最佳布局时,<TT><FONT 
  face=新宋体>operator()</FONT></TT>方法也和<TT><FONT 
  face=新宋体>[][]</FONT></TT>方法一样简单(也许<TT><FONT 
  face=新宋体>operator()</FONT></TT>方法更容易一点点,但我不想夸大其词)。 
  <LI><FONT face=新宋体><TT>operator()</TT><TT> 
  </TT></FONT>方法有时更好,是因为当对于给定的应用,有其它比以行为主的密集矩阵更好的布局时,用 <TT><FONT 
  face=新宋体>operator()</FONT></TT> 方法比<TT><FONT 
  face=新宋体>[][]</FONT></TT>方法实现会容易得多。 </LI></UL>
<P>作为一个物理布局使得实现困难的例子,最近的项目发生在以列访问矩阵元素(也就是,算法访问一列中的所有元素,然后是另一列等),如果物理布局是以行为主的,对矩阵的访问可能会“cache失效”。例如,如果行的大小几乎和处理器的cache大小相当,那么对每个元素的访问,都会发生“cache不命中”。在这个特殊的项目中,我们通过将映射从逻辑布局(行,列)变为物理布局(列,行),性能得到了20%的提升。 

<P>当然,还有很多这类事情的例子,而稀疏矩阵在这个问题中则是又一类例子。通常,使用<TT><FONT 
face=新宋体>operator()</FONT></TT>方法实现一个稀疏矩阵或交换行/列顺序更容易,<TT><FONT 
face=新宋体>operator()</FONT></TT>方法不会损失什么,而可能获得一些东西——它不会更差,却可能更好。 
<P>使用 <A 
href="http://www.sunistudio.com/cppfaq/operator-overloading.html#[13.8]"><TT><FONT 
face=新宋体>operator()</FONT></TT> 方法</A>。 
<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/operator-overloading.html#top">Top</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/operator-overloading.html#bottom">Bottom</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/assignment-operators.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/friends.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=[13.10]></A>
<DIV class=FaqTitle>
<H3>[13.10] 该从外(接口优先)还是从内(数据优先)设计类?<IMG alt=UPDATED! 
src="C++ FAQ Lite[13]--算符重载(新).files/updated.gif"></H3></DIV><SMALL><EM>[Recently 
changed so it uses new-style headers and the <TT><FONT 
face=新宋体>std::</FONT></TT> syntax and reworded references to STL (on 7/00). <A 
href="http://www.sunistudio.com/cppfaq/friends.html#[14.2]">Click here to go to 
the next FAQ in the "chain" of recent 
changes<!--rawtext:[14.2]:rawtext--></A>.]</EM></SMALL> 
<P>从外部! 
<P>良好的接口提供了一个<A 
href="http://www.sunistudio.com/cppfaq/classes-and-objects.html#[7.3]">简化的,以用户词汇表达的视图</A>。在面向对象软件的情况下,接口通常是单个类或<A 
href="http://www.sunistudio.com/cppfaq/friends.html#[14.2]">一组紧密结合的类</A>的public方法的集合. 

<P>首先考虑对象的逻辑特征是什么,而不是打算如何创建它。例如,假设要创建一个<TT><FONT 
face=新宋体>Stack</FONT></TT>(栈)类,其包含一个 <TT><FONT face=新宋体>LinkedList</FONT></TT>: 
<P>  
<DIV class=CodeBlock><TT><FONT 
face=新宋体>&nbsp;class&nbsp;Stack&nbsp;{<BR>&nbsp;public:<BR>&nbsp;&nbsp;&nbsp;</FONT></TT><EM>//&nbsp;...</EM><TT><BR><FONT 
face=新宋体>&nbsp;private:<BR>&nbsp;&nbsp;&nbsp;LinkedList&nbsp;list_;<BR>&nbsp;}; 
</FONT></TT></DIV>
<P>Stack是否应该有一个返回<TT><FONT face=新宋体>LinkedList</FONT></TT>的<TT><FONT 
face=新宋体>get()</FONT></TT>方法?或者一个带有<TT><FONT 
face=新宋体>LinkedList</FONT></TT>的<TT><FONT 
face=新宋体>set()</FONT></TT>方法?或者一个带有<TT><FONT 
face=新宋体>LinkedList</FONT></TT>的构造函数?显然,答案是“不”,因为应该从外向里设计接口。也就是说,<TT><FONT 
face=新宋体>Stack</FONT></TT>对象的用户并不关心 <TT><FONT 
face=新宋体>LinkedList</FONT></TT>;他们只关心 pushing 和 popping。 
<P>现在看另一个更微妙的例子。假设 <TT><FONT face=新宋体>LinkedList</FONT></TT>类使用<TT><FONT 
face=新宋体>Node</FONT></TT>对象的链表来创建,每一个<TT><FONT 
face=新宋体>Node</FONT></TT>对象有一个指向下一个<TT><FONT face=新宋体>Node</FONT></TT>的指针: 
<P>  
<DIV class=CodeBlock><TT><FONT 
face=新宋体>&nbsp;class&nbsp;Node&nbsp;{&nbsp;</FONT></TT><EM>/*...*/</EM><TT><FONT 
face=新宋体>&nbsp;};<BR>&nbsp;<BR>&nbsp;class&nbsp;LinkedList&nbsp;{<BR>&nbsp;public:<BR>&nbsp;&nbsp;&nbsp;</FONT></TT><EM>//&nbsp;...</EM><TT><BR><FONT 
face=新宋体>&nbsp;private:<BR>&nbsp;&nbsp;&nbsp;Node*&nbsp;first_;<BR>&nbsp;}; 
</FONT></TT></DIV>
<P><TT><FONT face=新宋体>LinkedList</FONT></TT>类是否应该有一个让用户访问第一个<TT><FONT 
face=新宋体>Node</FONT></TT>的<TT><FONT face=新宋体>get()</FONT></TT>方法?<FONT 
face=新宋体><TT>Node</TT><TT> </TT></FONT>对象是否应该有一个让用户访问链中下一个 <FONT 
face=新宋体><TT>Node</TT><TT> </TT></FONT>的 <TT><FONT 
face=新宋体>get()</FONT></TT>方法?换句话说,从外部看,<TT><FONT 
face=新宋体>LinkedList</FONT></TT>应该是什么样的?<TT><FONT face=新宋体>LinkedList 
</FONT></TT>是否实际上就是一个 <TT><FONT face=新宋体>Node 
</FONT></TT>对象的链?或者这些只是实现的细节?如果只是实现的细节,<TT><FONT face=新宋体>LinkedList 
</FONT></TT>将如何让用户在某时刻访问 <TT><FONT face=新宋体>LinkedList </FONT></TT>中的每一个元素? 
<P>某人的回答:<TT><FONT face=新宋体>LinkedList </FONT></TT>不是的 <TT><FONT face=新宋体>Node 
</FONT></TT>链。它可能的确是用&nbsp; <TT><FONT face=新宋体>Node 
</FONT></TT>创建的,但这不是本质。它的本质是元素的序列。因此,<TT><FONT face=新宋体>LinkedList</FONT></TT> 
抽象应该提供一个“LinkedListIterator”,并且“LinkedListIterator”应该有一个<TT><FONT 
face=新宋体>operator++</FONT></TT> 来访问下一个元素,并且有一对<TT><FONT 
face=新宋体>get()</FONT></TT>/<TT><FONT face=新宋体>set()</FONT></TT>来访问存储于<TT><FONT 
face=新宋体>Node</FONT></TT> 的值(<TT><FONT face=新宋体>Node</FONT></TT> 
元素中的值只由<TT><FONT face=新宋体>LinkedList</FONT></TT>用户负责,因此有一对<TT><FONT 
face=新宋体>get()</FONT></TT>/<TT><FONT face=新宋体>set()</FONT></TT>以允许用户自由地维护该值)。 
<P>从用户的观点出发,我们可能希望 <TT><FONT 
face=新宋体>LinkedList</FONT></TT>类支持看上去类似使用指针算法访问数组的算符: 
<P>  
<DIV class=CodeBlock><TT><FONT 
face=新宋体>&nbsp;void&nbsp;userCode(LinkedList&amp;&nbsp;a)<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;for&nbsp;(LinkedListIterator&nbsp;p&nbsp;=&nbsp;a.begin();&nbsp;p&nbsp;!=&nbsp;a.end();&nbsp;++p)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&lt;&lt;&nbsp;*p&nbsp;&lt;&lt;&nbsp;'\n';<BR>&nbsp;} 
</FONT></TT></DIV>
<P>实现这个接口,<TT><FONT face=新宋体>LinkedList</FONT></TT>需要一个 <TT><FONT 
face=新宋体>begin()</FONT></TT>方法和 <TT><FONT 
face=新宋体>end()</FONT></TT>方法。它们返回一个“LinkedListIterator”对象。该“LinkedListIterator”需要一个前进的方法,<TT><FONT 
face=新宋体>++p</FONT></TT> ;访问当前元素的方法,<TT><FONT 
face=新宋体>*p</FONT></TT>;和一个比较算符,<TT><FONT 
face=新宋体>p&nbsp;!=&nbsp;a.end()</FONT></TT>。 

⌨️ 快捷键说明

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