C++Primer 第13章复制控制课后习题答案文档格式.docx

上传人:b****1 文档编号:356183 上传时间:2023-04-28 格式:DOCX 页数:22 大小:35.37KB
下载 相关 举报
C++Primer 第13章复制控制课后习题答案文档格式.docx_第1页
第1页 / 共22页
C++Primer 第13章复制控制课后习题答案文档格式.docx_第2页
第2页 / 共22页
C++Primer 第13章复制控制课后习题答案文档格式.docx_第3页
第3页 / 共22页
C++Primer 第13章复制控制课后习题答案文档格式.docx_第4页
第4页 / 共22页
C++Primer 第13章复制控制课后习题答案文档格式.docx_第5页
第5页 / 共22页
C++Primer 第13章复制控制课后习题答案文档格式.docx_第6页
第6页 / 共22页
C++Primer 第13章复制控制课后习题答案文档格式.docx_第7页
第7页 / 共22页
C++Primer 第13章复制控制课后习题答案文档格式.docx_第8页
第8页 / 共22页
C++Primer 第13章复制控制课后习题答案文档格式.docx_第9页
第9页 / 共22页
C++Primer 第13章复制控制课后习题答案文档格式.docx_第10页
第10页 / 共22页
C++Primer 第13章复制控制课后习题答案文档格式.docx_第11页
第11页 / 共22页
C++Primer 第13章复制控制课后习题答案文档格式.docx_第12页
第12页 / 共22页
C++Primer 第13章复制控制课后习题答案文档格式.docx_第13页
第13页 / 共22页
C++Primer 第13章复制控制课后习题答案文档格式.docx_第14页
第14页 / 共22页
C++Primer 第13章复制控制课后习题答案文档格式.docx_第15页
第15页 / 共22页
C++Primer 第13章复制控制课后习题答案文档格式.docx_第16页
第16页 / 共22页
C++Primer 第13章复制控制课后习题答案文档格式.docx_第17页
第17页 / 共22页
C++Primer 第13章复制控制课后习题答案文档格式.docx_第18页
第18页 / 共22页
C++Primer 第13章复制控制课后习题答案文档格式.docx_第19页
第19页 / 共22页
C++Primer 第13章复制控制课后习题答案文档格式.docx_第20页
第20页 / 共22页
亲,该文档总共22页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

C++Primer 第13章复制控制课后习题答案文档格式.docx

《C++Primer 第13章复制控制课后习题答案文档格式.docx》由会员分享,可在线阅读,更多相关《C++Primer 第13章复制控制课后习题答案文档格式.docx(22页珍藏版)》请在冰点文库上搜索。

C++Primer 第13章复制控制课后习题答案文档格式.docx

:

string),i(0),d(0){}

private:

std:

string*pstring;

inti;

doubled;

};

NoName(constNoName&

orig):

pstring(newstring(*(orig.pstring))),i(orig.i),d(orig.d)

{

//pstring=newstring;

//*pstring=*(orig.pstring);

5.哪个类定义可能需要一个复制构造函数?

(a)包含四个float成员的Point3w类。

(b)Matrix类,其中,实际矩阵在构造函数中动态分配,在析构函数中删除。

(c)Payroll类,在这个类中为每个对象提供唯一ID。

(d)Word类,包含一个string和一个以行列位置对为元素的vector。

(b)需要,涉及到指针及动态分配

(c)需要,在根据已存在的Payroll对象创建其副本时,需要提供唯一的ID.

其他的均可以调用编译器的提供的复制构造函数,或者调用类类型的string和vector的复制构造函数。

6.复制构造函数的形参并不限制为const,但必须是一个引用,解释这个限制的基本原理,例如,解释为什么下面的定义不能工作,

Sales_item:

Sales_item(constSales_itemrhs);

它不能工作的原因是:

当形参为非引用类型时,将复制实参的值,给这个copyconstructor,但是,每当以传值方式传递参数时,会导致调用复制构造函数,因此,如果要使用以传值方式传递参数的copyconstructor,必须使用一个“不以传值方式传递参数”的copyconstructor,否则就会导致copyconstructor的无穷递归调用。

这个“不以传值方式传递参数”的方法就是使用形参是一个引用的copyconstructor,即以传地址的方式传递参数。

7.类何时需要定义复制操作符?

在需要定义复制构造函数时,也需要定义赋值操作符,即如果一个类

(1)类中包含指针型数据成员,

(2)或者在进行赋值操作时需要做一些特定工作,则该类需要定义赋值操作符。

8.对于习题13.5中列出的每个类型,指出类是否需要赋值操作符。

(b)需要赋值操作符,因为涉及指针和动态分配内存;

(c)需要,在用已存在的Payroll对象给另一个Payroll对象赋值时,需要提供唯一的ID。

9.习题13.4中包括NoName类的简单定义,确定这个类是否需要赋值操作符,如果需要,实现它。

因为有指针类的数据成员,所以需要赋值操作符,实现为:

NoName&

operator=(constNoName&

Nn)

i(Nn.i);

d(Nn.d);

pstring=newstring;

*pstring=*(Nn.pstring);

return*this;

10.定义一个Employee类,包含雇员名字和一个唯一的雇员标识,为该类定义默认构造函数和参数为表示雇员名字的string构造函数。

如果该类需要复制构造函数或赋值操作符,实现这些函数。

classEmployee

public:

Employee():

ID(cnt){cnt++;

}//默认构造函数

Employee(conststd:

string&

na):

name(na),ID(cnt)

{cnt++;

}//构造函数

//拷贝构造函数

Employee(constEmployee&

rhs):

name(rhs.name),ID(cnt)

{cnt++;

}

//赋值操作符

Employee&

operator=(constEmployee&

rhs)

{

name=rhs.name;

return*this;

stringname;

intID;

staticintcnt;

另外需要在类外对static成员进行初始化:

intEmployee:

cnt=1;

11.什么是析构函数?

合成析构函数有什么用?

什么时候会合成析构函数?

什么时候一个类必须定义自己的析构函数?

析构函数是一个成员函数,它的名字与类的名字相同,在名字前加一个代字符~,没有返回值,没有形参,用于类的对象超出作用域时释放对象所获取的资源,或删除指向动态分配对象的指针。

合成析构函数的作用:

1,按对象创建时的逆序撤销每个非static成员,2,对于类类型的成员,合成析构函数调用该成员的析构函数来撤销对象。

编译器总会为每个类合成一个析构函数。

当1,需要释放指针成员的资源时,2,需要执行某些特定工作时,必须自己定义析构函数。

12.确定在习题13.4中概略定义的NoName类是否需要析构函数,如果需要,实现它。

根据“三法则”需要显式定义析构函数,实现为:

NoName:

~NoName

deletepstring;

13.理解复制控制成员和构造函数的一个良好方式是定义一个简单类,该类具有这些成员,每个成员打印自己的名字:

structExmp1{

Exmp1(){std:

cout<

<

“Exmp1()”<

endl;

Exmp1(constExmp1&

{std:

“Exmp1(constExmp1&

)”<

//…

编写一个像Exmp1这样的类,给出复制控制成员和其他构造函数。

然后写一个程序,用不同方式使用Exmp1类型的对象:

作为非引用和引用形参传递,动态分配,放在容器中,等等,研究何时执行哪个构造函数和复制控制成员,可以帮助你融会贯通第理解这些概念。

//13.14_CopyControlMember.cpp:

定义控制台应用程序的入口点。

//

#include"

stdafx.h"

#include<

iostream>

vector>

classExmp

//constructor

Exmp()

{

std:

"

UsingExmp()."

<

//

//copyconstructor

Exmp(constExmp&

UsingExmp(constExmp&

)_copyconstructor."

//overloadoperator

Exmp&

operator=(constExmp&

UsingExmp&

)_overloadoperator."

//destructor

~Exmp()

Using~Exmp()."

voidfunc1(Exmpobj)//形参为Exmp的对象

}

voidfunc2(Exmp&

obj)//形参为Exmp对象的引用

Exmpfunc3()

Exmpobj;

returnobj;

//返回exmp对象

int_tmain(intargc,_TCHAR*argv[])

Exmpexmp1;

Exmpexmp2(exmp1);

exmp2=exmp2;

func1(exmp1);

func2(exmp1);

exmp1=func3();

Exmp*p=newExmp;

Exmp>

evec(3);

deletep;

system("

pause"

);

return0;

15.下面的代码中发生了多少次析构函数的调用?

voidfcn(constSales_item*trans,Sales_itemaccm)

Sales_itemitem1(*trans),item2(accm);

if(!

item1.same_isbn(item2))return;

if(item1.avg_price()<

=99)return;

elseif(item2.avg_price()<

3次,分别用在当函数执行完毕后的撤销非static的形参对象accm和局部对象item1,item2.

16.编写本节中描述的Message类。

classMessage

Message(conststd:

str="

"

):

contents(str){}

Message(constMessage&

Message&

operator=(constMessage&

~Message();

voidsave(Folder&

voidremove(Folder&

voidaddFldr(Folder*);

voidremFldr(Folder*);

stringcontents;

set<

Folder*>

folders;

voidput_Msg_in_Folders(conststd:

&

voidremove_Msg_from_Folders();

Message:

Message(constMessage&

m):

contents(m.contents),folders(m.folders)

put_Msg_in_Folders(folders);

voidMessage:

put_Msg_in_Folders(conststd:

&

rhs)

for(std:

const_iteratorbeg=rhs.begin();

beg!

=rhs.end();

++beg)

(*beg)->

addMsg(this);

Message&

Message:

operator=(constMessage&

rhs)

if(&

rhs!

=this)

remove_Msg_from_Folders();

contents=rhs.contents;

folders=rhs.folders;

put_Msg_in_Folders(rhs.folders);

remove_Msg_from_Folders()

const_iteratorbeg=folders.begin();

=folders.end();

remMsg(this);

~Message()

remove_Msg_from_Folders();

save(Folder&

fldr)

addFldr(&

fldr);

fldr.remMsg(this);

remove(Folder&

fldr)

remFldr(&

addFldr(Folder*fldr)

folders.insert(fldr);

remFldr(Folder*fldr)

folders.erase(fldr);

17.为message类增加与Folder的addMsg和remMsg操作类似的函数。

这些函数可以命名为addFldr和remFldr,应接受一个指向Folder的指针并将该指针插入到folders。

这些函数可为private的,因为它们将仅在Message类的实现中使用。

addFldr(Folder*fldr)

18.编写相应的Folder类。

该类应保存一个set<

Message*>

包含指向Message的元素。

classMessage;

classFolder

Folder(){}

Folder(constFolder&

Folder&

operator=(constFolder&

~Folder();

voidsave(Message&

voidremove(Message&

voidaddMsg(Message&

voidremMsg(Message&

messages;

voidput_Fldr_In_Messages(conststd:

voidremove_Fldr_Messages();

Folder:

Folder(constFolder&

f):

messages(f.messages)

put_Fldr_In_Messages(messages);

voidFolder:

put_Fldr_In_Messages(conststd:

for(std:

++beg)

addFldr(this);

Folder&

Folder:

operator=(constFolder&

=this)

remove_Fldr_Messages();

messages=rhs.messages;

put_Fldr_In_Messages(rhs.messages);

remove_Fldr_Messages()

for(std:

const_iteratorbeg=messages.begin();

beg!

=messages.end();

remFldr(this);

~Folder()

remove_Fldr_Messages();

save(Message&

msg)

addMsg(&

msg);

msg.addFldr(this);

remove(Message&

remMsg(&

msg.remFldr(this);

addMsg(Message&

messages.insert(mag);

remMsg(Message&

messages.erase(msg);

19.在Message类和Folder类中增加save和remove操作,这些操作应接受一个Folder,并将该Folder加入到指向这个Message的Folder集中(或从其中删除该Folder)。

操作还必须更新Folder以反映它指向该Message,这可以通过调用addMsg或remMsg完成。

20.对于HasPtr类的原始版本(依赖于复制控制的默认定义),描述下面代码中会发生什么:

inti=42;

HasPtrp1(&

i,42);

HasPtrp2=p1;

p2.get_ptr_val()<

endll;

输出42

p1.set_ptr_val(0);

endl;

输出0

21.如果给HasPtr类添加一个析构函数,用来删除指针成员,会发生什么?

如果这样,则撤销一个HasPtr对象时会删除其指针成员所指向的对象,从而使得当一个HasPtr对象被撤消后,其他由该对象复制而创建的HasPtr对象中的指针成员也无法使用。

22.什么是使用计数?

使用计数是复制控制成员中使用的编程技术。

将一个计数器与类指向的对象相关联,用于跟踪该类有多少个对象共享同一指针。

创建一个单独类指向共享对象并管理使用计数。

由构造函数设置共享对象的状态并将使用计数置为1。

每当由复制构造函数或赋值操作符生成一个新副本时,使用计数加1。

由析构函数撤销对象或作为赋值操作符的左操作数撤销对象时,使用计数减少1。

赋值操作符和析构函数检查使用计数是否已减至0,若是,则撤销对象。

23.什么是智能指针?

智能指针如何与实现普通指针行为的类相区别?

智能指针式一个行为类似指针但也提供其他功能的类。

这个类与实现普通指针行为的类区别在于:

智能指针通常接受指向动态分配对象的指针并负责删除该对象。

用户分配对象,但由智能指针类删除它,因此智能指针类需要实现赋值控制成员来管理指向共享对象的指针。

只有在撤销了指向共享对象的最后一个智能指针后,才能删除该共享对象。

使用计数就是实现智能指针类最常用的一个方式。

24.实现你自己的使用计数式HasPtr类的版本。

classU_Ptr

friendclassHasPtr;

int*ip;

size_tuse;

U_Ptr(int*p):

ip(p),use

(1){}

~U_Ptr(){deleteip;

classHasPtr

HasPtr(int*p,inti):

ptr(newU_Ptr(p),val(i){}

HasPtr(constHasPtr&

rhs):

ptr(rhs.ptr),val(rhs.val)

++ptr->

use;

HasPtr&

operator=(constHasPtr&

~HasPtr()

if(--ptr->

use==0)deleteptr;

int*get_ptr()const{returnptr->

ip;

intget_int()const{returnval;

voidset_ptr(int*p){ptr->

ip=p;

voidset_int(inti){val=i;

intget_ptr_val()const{return*ptr->

voidset_ptr_val(inti){*ptr->

ip=i;

U_Ptr*ptr;

intval;

HasPtr&

HasPtr:

operator=(constHasPtr&

++rhs.ptr->

if(--ptr->

use==0)

deleteptr;

ptr=rhs.ptr;

val=rhs.val;

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

当前位置:首页 > 职业教育 > 其它

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2