📄 effective c++ 2e item16.htm
字号:
<P> // assign to all data members<BR> name =
rhs.name;
// 给name赋值</P>
<P> *ptr =
*rhs.ptr;
//
对于ptr,赋的值是指针所指的值,<BR>
// 不是指针本身</P>
<P> return
*this;
// 见条款15<BR>}</P>
<P>初写这个类时当然很容易记住上面的原则,但同样重要的是,当类里增加新的数据成员时,也要记住更新赋值运算符函数。例如,打算升级NamedPtr模板使得名字改变时附带一个时间标记,那就要增加一个新的数据成员,同时需要更新构造函数和赋值运算符。但现实中,因为忙于升级类的具体功能和增加新的成员函数等,这一点往往很容易被忘记。</P>
<P>当涉及到继承时,情况就会更有趣,因为派生类的赋值运算符也必须处理它的基类成员的赋值!看看下面:</P>
<P>class Base {<BR>public:<BR> Base(int initialValue = 0): x(initialValue)
{}</P>
<P>private:<BR> int x;<BR>};</P>
<P>class Derived: public Base {<BR>public:<BR> Derived(int
initialValue)<BR> : Base(initialValue), y(initialValue) {}</P>
<P> Derived& operator=(const Derived& rhs);</P>
<P>private:<BR> int y;<BR>};</P>
<P>逻辑上说,Derived的赋值运算符应该象这样:</P>
<P>// erroneous assignment operator<BR>Derived& Derived::operator=(const
Derived& rhs)<BR>{<BR> if (this == &rhs) return
*this; // 见条款17</P>
<P> y =
rhs.y;
//
给Derived仅有的<BR>
// 数据成员赋值</P>
<P> return
*this;
// 见条款15<BR>}</P>
<P>不幸的是,它是错误的,因为Derived对象的Base部分的数据成员x在赋值运算符中未受影响。例如,考虑下面的代码段:</P>
<P>void assignmentTester()<BR>{<BR> Derived
d1(0);
// d1.x = 0, d1.y = 0<BR> Derived
d2(1);
// d2.x = 1, d2.y = 1</P>
<P> d1 = d2; // d1.x = 0,
d1.y = 1!<BR>}</P>
<P>请注意d1的Base部分没有被赋值操作改变。</P>
<P>解决这个问题最显然的办法是在Derived::operator=中对x赋值。但这不合法,因为x是Base的私有成员。所以必须在Derived的赋值运算符里显式地对Derived的Base部分赋值。</P>
<P>也就是这么做:</P>
<P>// 正确的赋值运算符<BR>Derived& Derived::operator=(const Derived&
rhs)<BR>{<BR> if (this == &rhs) return *this;</P>
<P> Base::operator=(rhs); //
调用this->Base::operator=<BR> y = rhs.y;</P>
<P> return *this;<BR>}</P>
<P>这里只是显式地调用了Base::operator=,这个调用和一般情况下的在成员函数中调用另外的成员函数一样,以*this作为它的隐式左值。Base::operator=将针对*this的Base部分执行它所有该做的工作——正如你所想得到的那种效果。</P>
<P>但如果基类赋值运算符是编译器生成的,有些编译器会拒绝这种对于基类赋值运算符的调用(见条款45)。为了适应这种编译器,必须这样实现Derived::operator=:</P>
<P>Derived& Derived::operator=(const Derived& rhs)<BR>{<BR> if
(this == &rhs) return *this;</P>
<P> static_cast<Base&>(*this) =
rhs; //
对*this的Base部分<BR>
// 调用operator= <BR> y = rhs.y;</P>
<P> return *this;<BR>}</P>
<P>这段怪异的代码将*this强制转换为Base的引用,然后对其转换结果赋值。这里只是对Derived对象的Base部分赋值。还要注意的重要一点是,转换的是Base对象的引用,而不是Base对象本身。如果将*this强制转换为Base对象,就要导致调用Base的拷贝构造函数,创建出来的新对象(见条款M19)就成为了赋值的目标,而*this保持不变。这不是所想要的结果。</P>
<P>不管采用哪一种方法,在给Derived对象的Base部分赋值后,紧接着是Derived本身的赋值,即对Derived的所有数据成员赋值。</P>
<P>另一个经常发生的和继承有关的类似问题是在实现派生类的拷贝构造函数时。看看下面这个构造函数,其代码和上面刚讨论的类似:</P>
<P>class Base {<BR>public:<BR> Base(int initialValue = 0): x(initialValue)
{}<BR> Base(const Base& rhs): x(rhs.x) {}</P>
<P>private:<BR> int x;<BR>};</P>
<P>class Derived: public Base {<BR>public:<BR> Derived(int
initialValue)<BR> : Base(initialValue), y(initialValue) {}</P>
<P> Derived(const Derived& rhs) //
错误的拷贝<BR> : y(rhs.y)
{}
// 构造函数</P>
<P>private:<BR> int y;<BR>};</P>
<P>类Derived展现了一个在所有C++环境下都会产生的bug:当Derived的拷贝创建时,没有拷贝其基类部分。当然,这个Derived对象的Base部分还是创建了,但它是用Base的缺省构造函数创建的,成员x被初始化为0(缺省构造函数的缺省参数值),而没有顾及被拷贝的对象的x值是多少!</P>
<P>为避免这个问题,Derived的拷贝构造函数必须保证调用的是Base的拷贝构造函数而不是Base的缺省构造函数。这很容易做,只要在Derived的拷贝构造函数的成员初始化列表里对Base指定一个初始化值:</P>
<P>class Derived: public Base {<BR>public:<BR> Derived(const Derived&
rhs): Base(rhs), y(rhs.y) {}</P>
<P> ...</P>
<P>};</P>
<P>现在,当用一个已有的同类型的对象来拷贝创建一个Derived对象时,它的Base部分也将被拷贝了。<BR></P><BR><BR></DIV></DIV></DIV><BR><BR>
<SCRIPT src="Effective C++ 2e Item16.files/get_readnum.htm"></SCRIPT>
<TABLE cellSpacing=1 cellPadding=2 width=770 align=center bgColor=#666666
border=0>
<TBODY>
<TR>
<TH id=white bgColor=#990000><FONT
color=#ffffff>对该文的评论</FONT></TH></TR></TBODY></TABLE><BR>
<SCRIPT language=javascript>
<!--
function isEmpty(s)
{
return ((s == null) || (s.length == 0))
}
function submit1()
{
if (isEmpty(document.add_critique.csdnname.value) || isEmpty(document.add_critique.csdnpassword.value) || isEmpty(document.add_critique.critique_content.value))
{
alert('登陆名,密码,评论不能为空!!!!') ;
return false;
}
document.add_critique.submit();
}
//-->
</SCRIPT>
<TABLE cellSpacing=1 cellPadding=2 width=770 align=center bgColor=#666666
border=0>
<TBODY>
<TR>
<TH id=white bgColor=#990000><FONT
color=#ffffff>发表评论</FONT></TH></TR></TBODY></TABLE>
<TABLE cellSpacing=1 cellPadding=2 width=770 align=center bgColor=#ffffff
border=0>
<TBODY>
<TR>
<TD>
<FORM name=add_critique action=/develop/add_critique.asp
method=post><INPUT type=hidden value=add name=critique_add> <INPUT
type=hidden value=8731 name=from> 评论人: <INPUT name=csdnname>
密码: <INPUT type=password name=csdnpassword>
评论:<BR> <TEXTAREA name=critique_content rows=8 cols=100></TEXTAREA><BR>
<INPUT onclick=javascript:submit1(); type=button value=发表评论 name=ubmit>
<INPUT type=hidden value=8731 name=id> </FORM></TD></TR></TBODY></TABLE>
<TABLE width=770 border=0>
<TBODY>
<TR>
<TD>
<TABLE cellPadding=2 width=770 border=0>
<TBODY>
<TR>
<TD height=10></TD></TR>
<TR>
<TD align=left width=130><A
href="http://www.csdn.net/news/looknews.asp?id=2313"
target=_blank><IMG src="http://www.csdn.net/job/images/csdn_job.gif"
border=0></A> </TD>
<TD align=middle width=510>
<OBJECT id=Movie1
codeBase=http://active.macromedia.com/flash2/cabs/swflash.cab#version=4,0,0,0
height=60 width=468
classid=clsid:D27CDB6E-AE6D-11cf-96B8-444553540000><PARAM NAME="movie" VALUE="http://www.csdn.net/images/ad/csdn_media.swf"><PARAM NAME="quality" VALUE="high">
<EMBED src="http://www.csdn.net/images/ad/csdn_media.swf"
quality=high WIDTH=468 HEIGHT=60
TYPE="application/x-shockwave-flash"
PLUGINSPAGE="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash">
</EMBED> </OBJECT></TD>
<TD align=middle width=130><A
href="http://www.hd315.gov.cn/beian/view.asp?bianhao=010202001032100010"><IMG
src="http://www.csdn.net/images/biaoshi.gif" border=0></A>
</TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD>
<TABLE height=20 cellSpacing=0 cellPadding=0 width=770 align=default
bgColor=#1f60a0 border=0>
<TBODY>
<TR class=font13px vAlign=center align=middle>
<TD class=font13px vAlign=center width=90 height=2></TD>
<TD width=2 rowSpan=2><IMG height=13
src="http://www.csdn.net/images/ad4.gif" width=2></TD>
<TD class=font13px width=90 height=2></TD>
<TD width=3 rowSpan=2><FONT color=#ffffff><IMG height=13
src="http://www.csdn.net/images/ad4.gif" width=2></FONT></TD>
<TD class=font13px width=90 height=2></TD>
<TD width=2 rowSpan=2><IMG height=13
src="http://www.csdn.net/images/ad4.gif" width=2></TD>
<TD class=font13px width=90 height=2></TD>
<TD width=3 rowSpan=2><FONT color=#ffffff><IMG height=13
src="http://www.csdn.net/images/ad4.gif" width=2></FONT></TD>
<TD width=350 height=2><FONT color=#ffffff></FONT></TD>
<TD width=10 rowSpan=2><FONT color=#ffffff><IMG height=11
src="http://www.csdn.net/images/ad3.gif" width=6></FONT></TD>
<TD class=font13px width=60 height=2></TD></TR>
<TR class=font14px vAlign=center align=middle>
<TD class=font13px vAlign=center width=90><A
href="http://www.csdn.net/intro/intro.shtm"><FONT
color=#ffffff>美达美简介</FONT></A></TD>
<TD class=font13px width=90><A
href="http://www.csdn.net/intro/ad.shtm"><FONT
color=#ffffff>广告服务</FONT></A></TD>
<TD class=font13px width=90><A
href="http://www.csdn.net/English/"><FONT
color=#ffffff>英语步步高</FONT></A></TD>
<TD class=font13px width=90><A href="http://www.csdn.net/dev/"><FONT
color=#ffffff>程序员大本营</FONT></A></TD>
<TD align=right width=350><SPAN class=font13px><A
href="mailto:webmaster@csdn.net"><FONT
color=#ffffff>百联美达美科技有限公司</FONT></A></SPAN><FONT color=#ffffff><SPAN
class=font13px> </SPAN></FONT></TD>
<TD class=font13px width=60><FONT color=#ffffff>版权所有</FONT>
<SCRIPT>document.write("<img src=http://202.106.156.10/stat.asp?user=designol&refer="+escape(document.referrer)+"&cur="+escape(document.URL)+" width=0 height=0 border=0>");</SCRIPT>
</TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></CENTER></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -