C++Primer第4版习题解答十四章.docx

上传人:b****5 文档编号:7262264 上传时间:2023-01-22 格式:DOCX 页数:30 大小:106.71KB
下载 相关 举报
C++Primer第4版习题解答十四章.docx_第1页
第1页 / 共30页
C++Primer第4版习题解答十四章.docx_第2页
第2页 / 共30页
C++Primer第4版习题解答十四章.docx_第3页
第3页 / 共30页
C++Primer第4版习题解答十四章.docx_第4页
第4页 / 共30页
C++Primer第4版习题解答十四章.docx_第5页
第5页 / 共30页
点击查看更多>>
下载资源
资源描述

C++Primer第4版习题解答十四章.docx

《C++Primer第4版习题解答十四章.docx》由会员分享,可在线阅读,更多相关《C++Primer第4版习题解答十四章.docx(30页珍藏版)》请在冰豆网上搜索。

C++Primer第4版习题解答十四章.docx

C++Primer第4版习题解答十四章

第十四章重载操作符与转换

1。

在什么情况下重载操作符与内置操作符不同?

在什么情况下重载操作符与内置操作符相同?

重载操作符必须具有至少一个类类型或枚举类型的操作数。

重载操作符不保证操作数的求值顺序,例如对&&和||的重载版本不再具有“短路求值”的特性,两个操作数都要进行求值,而且不规定操作数的求值顺序。

对于优先级和结合性及操作数的数目都不变。

2。

为Sales_item编写输入、输出。

加以及复合赋值操作符的重载声明。

classSales_item

{

friendstd:

:

istream&operator>>(std:

:

istream&,Sales_item&);

friendstd:

:

ostream&operator<<(std:

:

ostream&,constSales_item&);

public:

Sales_item&operator+=(constSales_item&);

};

Sales_itemoperator+(constSales_item&,constSales_item&)

3。

解释如下程序,假定Sales_item构造函数的参数是一个string,且不为explicit.解释如果构造函数为explicit会怎样。

stringnull_book=“0-000-00000-0”;

Sales_itemitem(cin);

item+=null_book;

第一句:

调用接受一个C风格的字符串形参的string构造函数,创建一个string临时对象,然后使用string复制构造函数用这个临时对象初始化string对象null_book,

第二句:

从标准输入设备读入数据,创建Sales_item对象item。

第三句:

首先调用接受一个string参数的Sales_item构造函数,创建一个临时对象,然后调用Sales_item的复合重载操作符+=,将这个Sales_item临时对象加到item对象上,

如果构造函数为explicit,则不能进行从string对象到Sales_item对象的隐式转换,第三句将不能被编译。

4。

string和vector类都定义了一个重载的==,可用于比较这些类的对象,指出下面的表达式中应用了哪个==版本。

strings;vectorsvec1,svec2;

“cobble”==“store”应用了C++语言内置版本的重载==

svec1[0]==svec2[0];应用了string版本的重载==

svec1==svec2应用了vector版本的重载==

5。

列出必须定义为类成员的操作符。

赋值=,下标[],调用(),成员访问箭头->

6。

解释下面操作符是否应该为类成员,为什么?

(a)+(b)+=(c)++(d)->(e)<<(f)&&(g)==(h)()

+,<<,==,&&通常定义为非成员;->和()必须定义为成员,否则会出现编译错误;+=和++会改变对象的状态,通常会定义为类成员。

7。

为下面的ChecoutRecord类定义一个输出操作符:

classCheckoutRecord

{

public:

//..

private:

doublebook_id;

stringtitle;

Datedate_borrowed;

Datedate_due;

pairborrower;

vector*>wait_list;

};

ostream&

operator<<(ostream&out,constCheckoutRecord&s)

{

out<

<<"\t";

out<<"borrower:

"<

out<<"wait_list:

"<

for(vector*>:

:

const_iteratorit=s.wait_list.begin();

it!

=s.wait_list.end();++it)

{

out<<"\t"<<(*it)->first<<","<<(*it)->second<

}

returnout;

}

8。

在12.4节的习题中,你编写了下面某个类的框架:

(b)Date

为所选择的类编写输出操作符。

#include

usingnamespacestd;

classDate

{

public:

Date(){}

Date(inty,intm,intd)

{

year=y;month=m;day=d;

}

friendostream&operator<<(ostream&,constDate&);

private:

intyear,month,day;

};

ostream&

operator<<(ostream&out,constDate&d)

{

out<<"year:

"<

<<"month:

"<

<<"day:

"<

}

intmain()

{

Datedt(1988,12,01);

cout<

system("pause");

return0;

}

9。

给定下述输入,描述Sales_item输入操作符的行为。

(a)0-201-99999-91024.95

(b)1024.950-201-99999-9

(a)将0-201-99999-9读入赋给对象的isbn成员,将10给units_sold成员,revenue成员被设置为249.5

(b)首先将形参对象的isbn成员设置为10,然后因为输入的数据不符合要求,导致输入失败,从而执行else语句,将Sales_item对象复位为空对象,此时isbn为空string,units_sold和revenue都为0

10。

下述Sales_item输入操作符有什么错误?

istream&operator>>(istream&in,Sales_item&s)

{

doubleprice;

in>>s.isbn>>s.units_sold>>price;

s.revenue=s.units_sold*price;

returnin;

}

如果将习题14.9中的数据作为输入,将会发生什么?

上述的输入操作符中缺少了对错误输入情况的判断与处理,会导致错误的情况发生。

(a)的输入没有问题,但是(b)的输入,将形参Sales_item对象的ISBN成员值为10,units_sold和revenue成员保持原值不变。

11。

为14.2.1节习题中定义的CheckoutRecord类定义一个输入操作符,确保该类操作符处理输入错误。

classCheckoutRecord

{

public:

//…

friendistream&operator>>(istream&,CheckoutRecord&);//声明为类的友元

//…

};

istream&operator>>(istream&in,CheckoutRecord&c)

{

cout<<"Inputbookid(double)andtitle(string):

\n";

in>>c.book_id>>c.title;

//InputDatadata_borrowedanddata_due

cout<<"Inputdata_borrowed(3ints:

year,month,day):

\n";

in>>c.date_borrowed;//.year>>c.date_borrowed.month>>c.date_borrowed.day;

//InputDatadata_dueanddata_due

cout<<"Inputdata_due(3ints:

year,month,day):

\n";

in>>c.date_due;//.year>>c.date_due.month>>c.date_due.day;

//Inputthepairborrower

cout<<"Inputthepairborrower(string):

\n";

in>>c.borrower.first>>c.borrower.second;

if(!

in)

{

c=CheckoutRecord();

returnin;

}

//Inputwait_list

cout<<"Inputthewait_list(string):

\n";

c.wait_list.clear();

while(in)

{

pair*ppr=newpair;

in>>ppr->first>>ppr->second;

if(!

in)

{

deleteppr;

returnin;

}

c.wait_list.push_back(ppr);

}

returnin;

}

输入错误的情况:

输入正确的情况:

12。

编写Sales_item操作符,用+进行实际加法,而+=调用+。

与本节中操作符的实现方法相比较,讨论这个方法的缺点。

Sales_itemSales_item:

:

operator+(constSales_item&rhs)

{

units_sold+=rhs.units_sold;

revenue+=rhs.revenue;

return*this;

}

将下面定义的非成员+=操作符声明为类Sales_item的友元:

Sales_itemoperator+=(Sales_item&lhs,constSales_item&rhs)

{

lhs=lhs+rhs;

returnlhs;

}

这个方法缺点:

在+=操作中需要创建和撤销一个临时Sales_item对象,来保存+操作的结果,没有本节中的方法简单有效。

13。

如果有,你认为Sales_item还应该有哪些其他的算术操作符?

定义你认为的该类应包含的那些。

还应有-操作符,定义为类的非成员,相应地还应该有-=复合操作符并定义为类的成员。

Sales_item&Sales_item:

:

operator-=(constSalse_item&rhs)

{

units_sold-=rhs.units_sold;

revenue-=rhs.revenue;

return*this;

}

Sales_itemoperator-(constSales_item&lhs,constSales_item&rhs)

{

Sales_itemret(lhs);

ret-=rhs;

returnret;

}

14。

定义一个赋值操作符,将isbn赋值给Sales_item对象。

Sales_item&Sales_item:

:

operator=(conststring&s)

{

sbn=s;

return*this;

}

10。

为14.2.1节习题中介绍的CheckoutRecord类定义赋值操作符。

主函数中定义了两个CheckoutRecord类的对象,调用了CheckoutRecord类的=赋值操作符,效果如下截图:

int_tmain(intargc,_TCHAR*argv[])

{

CheckoutRecordc1;

cin>>c1;

CheckoutRecordc2;

c2=c1;//调用了类的赋值操作符=

std:

:

cout<

:

endl;//输出对象c2的内容

system("pause");

return0;

}

//CheckoutRecord类中赋值操作符定义为:

//重载操作符=

CheckoutRecord&CheckoutRecord:

:

operator=(constCheckoutRecord&cr)

{

book_id=cr.book_id;

title=cr.title;

date_borrowed=cr.date_borrowed;//前提:

必须在Date类里也重载操作符=

date_due=cr.date_due;//asbefore

//对pair进行赋值操作

borrower.first=cr.borrower.first;

borrower.second=cr.borrower.second;

//对vector进行赋值操作

wait_list.clear();//首先清空

for(vector*>:

:

const_iteratorit=cr.wait_list.begin();

it!

=cr.wait_list.end();++it)

{

pair*ppr=newpair;

ppr->first=(*it)->first;

ppr->second=(*it)->second;

wait_list.push_back(ppr);

}

return*this;

}

16。

CheckoutRecord类还应该定义其他赋值操作符吗?

如果是,解释哪些类型应该用作操作数并解释为什么。

为这些类型实现赋值操作符。

从应用角度考虑,可能会修改预约时间date_due,可通过设置新的赋值操作符来实现;或者是往wait_list里添加排队读者,也可以通过设置新的赋值操作符来实现。

//setnewdate_due

CheckoutRecord&CheckoutRecord:

:

operator=(const&new_due)

{

date_due=new_due;

return*this;

}

//addnewreaderswhowaitforsomebooks

CheckoutRecord&CheckoutRecord:

:

operator=(conststd:

:

pair&new_waiter)

{

pair*ppr=newpair;

*ppr=new_waiter;

wait_list.push_back(ppr);

return*this;

}

17。

14.2.1节习题中定义了一个CheckoutRecord类,为该类定义一个下标操作符,从等待列表中返回一个名字。

下标重载:

pair&CheckoutRecord:

:

operator[]

(constvector*>:

:

size_typeindex)

{

return*wait_list.at(index);

}

//下标操作符重载

constpair&CheckoutRecord:

:

operator[]

(constvector*>:

:

size_typeindex)const

{

return*wait_list.at(index);

}

18。

讨论用下标操作符实现这个操作的优缺点。

优点:

使用简单。

缺点:

操作的语义不够清楚,因为CheckoutRecord不是一个通常意义上的容器,而且等待者也不是CheckoutRecord容器中的一个元素,不易使人弄明白怎样用。

19。

提出另一种方法定义这个操作。

可以将这个操作定义成普通的函数,pair&get_a_waiter(constsize_tindex)和constpair&get_a_waiter(constsize_tindex)const.

20。

在ScreenPtr类的概略定义中,声明但没有定义赋值操作符,请实现ScreenPtr赋值操作符。

ScreenPtr&operator=(constScreenPtr&sp)

{

++sp.ptr->use;

if(--ptr->use==0)

deleteptr;

ptr=sp.ptr;

return*this;

}

21。

定义一个类,该类保存一个指向ScreenPtr的指针。

为该类定义一个重载的箭头操作符。

classNoName

{

public:

NoName(*p):

ps(newScreenPtr(p)){}

ScreenPtroperator->()

{

return*ps;

}

constScreenPtroperator->()const

{

return*ps;

}

~NoName()

{

deleteps;

}

private:

ScreenPtr*ps;

};

22。

智能指针可能应该定义相等操作符和不等操作符,以便测试两个指针是否相等或不等。

将这些操作加入到ScreenPtr类。

classScreenPtr

{

public:

//…

friendinlinebooloperator==(constScreenPtr&,constScreenPtr&);

friendinlinebooloperator!

=(constScreenPtr&,constScreenPtr&);

private:

ScrPtr*ptr;

};

//operator==

inlinebooloperator==(constScreenPtr&p1,constScreenPtr&p2)

{

returnp1.ptr==p2.ptr;

}

//operator!

=

inlinebooloperator!

=(constScreenPtr&p1,constScreenPtr&p2)

{

return!

(p1.ptr==p2-.ptr);

}

23。

CheckedPtr类表示指向数组的指针。

为该类重载下标操作符和解引用操作符。

使操作符确保CheckedPtr有效:

它应该不可能对超出数组末端的元素进行解引用或索引。

//下标操作符重载

int&CheckedPtr:

:

operator[](constsize_tindex)

{

if(beg+index>=end)

throwout_ot_range(“invalidindex“);

return*(beg+index);

}

constint&CheckedPtr:

:

operator[](constsize_tindex)const

{

if(beg+index>=end)

throwout_ot_range(“invalidindex“);

return*(beg+index);

}

//解引用操作符重载

intCheckedPtr:

:

operator*()

{

if(curr==end)

throwout_of_range(“invalidcurrentpointer”);

return*curr;

}

constint&CheckedPtr:

:

operator*()const

{

if(curr==end)

throwout_of_range(“invalidcurrentpointer”);

return*curr;

}

24。

习题14.23中定义的解引用操作符或下标操作符,是否也应该检查对数组起点之前的元素进行的解引用或索引?

解释你的答案。

对于下标操作符,应该进行检查,因为当用户给出的下标索引值小于0时,编译器不会出现编译错误,而会出现运行时错误。

应修改为:

//下标操作符重载

int&CheckedPtr:

:

operator[](constsize_tindex)

{

if(beg+index>=end||beg+index

throwout_ot_range(“invalidindex“);

return*(beg+index);

}

constint&CheckedPtr:

:

operator[](constsize_tindex)const

{

if(beg+index>=end||beg+index

throwout_ot_range(“invalidindex“);

return*(beg+index);

}

而对于解引用操作符,返回curr所指向的数组元素,在创建对象时已经将curr初始化为指向数组的第一个元素,只有当执行—操作时才会对curr进行减的操作,而—操作符已经对curr的值与数组起点进行了检查,所以不用再在这里检查。

25。

为了

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 农林牧渔 > 林学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1