C++primer13章习题

//13.3假定Point为类类型,该类类型有一个复制构造函数,指出下面程序段中每一个试用了复制构造函数的地方。

 

Point global;  //默认构造函数

Point foo_bar(Point arg)   //复制构造函数

{

    Pointlocal = arg;     //复制构造函数

    Point*heap =new Point(global);   //复制构造函数

    *heap= local;         

    Pointpa[ 4 ] = { loca, *heap };   //复制构造函数,复制构造函数,默认构造函数,默认构造函数

   return *heap;      //复制构造函数

}

 

//下边是测试程序

 

#include<iostream>

#include<stdlib.h>

usingnamespace std;

 

classPoint

{

public:

   int T;

public:

   staticint total;

    Point(int t=0);

   

    Point(const Point&a){T=a.T+1;  cout<<total++<<"复制构造函数"<<T<<endl;}

    ~Point(){cout<<total++<<"析构函数"<<T<<endl;}

 

};

intPoint::total=1;

Point::Point(intt):T(t){cout<<total++<<"构造函数"<<T<<endl;}

 

Point global(1);

Point foo_bar(Point arg)   //这里将会调用复制构造函数生成对象arg

{

    ::system("pause");

    Pointlocal = arg; //这里先用默认构造函数

    ::system("pause");

    Point*heap =new Point(global);

    ::system("pause");

    *heap= local;

    ::system("pause");

    Pointpa[ 4 ] = { local, *heap };

    ::system("pause");

   return *heap;

 

}

 

intmain()

{

    Pointarg(2);

    ::system("pause");

    foo_bar(arg);

   return 0;

}

 

 

//13.4对于如下的类的简单定义,编写一个复制构造函数复制所有成员,复制pstring指向的对象而不是复制指针

 

#include<iostream>

#include<string>

 

structNoName{

    NoName(std::stringstr ="abc"):pstring(new std::string(str)), i(0), d(0){}

    NoName(const NoName& T);

private:

    std::string*pstring;

   int i;

   double d;

};

NoName::NoName(constNoName& T)

{

    i= T.i;

    d= T.d;

    pstring=new std::string(*T.pstring);

    std::cout<<*pstring<<std::endl;

}

 

intmain()

{

    NoNameA;

    NoNameB(A);

   return 0;

}

 

 

//13.5哪个类定义可能需要一个复制构造函数

//a.包含四个float成员的Point3w类   

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

//c.Payroll类,在这个类中为每个对象提供唯一的ID

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

 

//b,c

 

 

//13.6复制构造函数的形参并不限制为const,但必须是一个引用。解释这个限制的基本原理。

//如果不是引用,会导致递归调用复制构造函数。

 

 

//13.7类何时需要定义赋值操作符

//也就是和需要复制构造函数一样的情况吧,一般就是指针的时候啊什么的

 

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

//同复制构造函数

 

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

 

 

structNoName{

    NoName(std::stringstr ="abc"):pstring(new std::string(str)), i(0), d(0){}

    NoName&operator=(constNoName& rhs);

private:

    std::string*pstring;

   int i;

   double d;

};

NoName& NoName::operator =(constNoName &rhs)

{

    i= rhs.i;

    d= rhs.d;

    pstring=new std::string(*rhs.pstring);

    return *this;

}

 

//13.10定义一个Employee类,包含雇员名字和一个唯一的雇员标识。

//为该类定义默认构造函数和参数为表示雇员名字的string的构造函数。

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

 

classEmployee{

private:

    std::stringname;

    std::stringID;

   staticint counter;

public:

    Employee():name("NoName"), ID(0) { counter++;}

    Employee(std::string_name): name(_name), ID(counter++){}

    Employee(const Employee& other):name(other.name),ID(counter++){}

    Employee&operator=(constEmployee& rhs);

}

 

intEmployee::counter = 1;

 

Employee& Employee::operator=(constEmployee &T)

{

    name= T.name;

   return *this;

}

 

//13.11什么是析构函数,合成析构函数有什么用,什么时候会合成析构函数,什么时候一个类必须定义自己的析构函数

//析构函数是特殊的成员函数,其名字是在类名字前加上一个代字号(~)。

//该函数没有返回值和形参,用于对象超出作用域或需要删除对象时来清除对象。

//合成析构函数的作用:按对象创建时的逆序(即成员在类中声明次序的逆序)撤销每个非static成员。

//对于类类型的成员,合成析构函数调用该成员的析构函数来撤销对象。

//编译器会为每个类合成析构函数。如果有些工作(如释放资源、执行特定操作等)需要析构函数完成,一个类就必须定义自己的析构函数。

 

 

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

 

NoName::~NoName()

{

   delete pstring;

}

 

//13.13确定在习题.10中定义的Employee类是否需要析构函数,如果需要实现它

//不需要

 

 

//13.14理解复制控制成员和构造函数的一个良好方式是定义一个简单类,该类具有这些成员

//每个成员打印自己的名字

 

#include<iostream>

#include<vector>

 

structExmpl{

    Exmpl(){ std::cout <<"Exmpl()"<< std::endl; }

    Exmpl(const Exmpl&)

        {std::cout <<"Exmpl(constExmpl&)" << std::endl; }

    Exmpl&operator= (constExmpl& )

        {std::cou <<"Exmpl& operator= (constExmpl&)" <<std::endl; }

    ~Exmpl(){ std::cout <<"~Exmpl()"<< std::endl; }

};

//编写一个像Exmpl这样的类,给出复制控制成员和其他构造函数,然后写一个程序,

//用不同方式使用Exmpl类型的对象:作为非引用形参和引用形参传递,动态分配,放在容器中,等等

//研究何时执行哪个构造哈数和复制控制成员,可以帮助你荣偶会贯通的理解这些概念

 

//程序有点长。。。反正也都理解了,就不写了,毕竟情况太多都打出来也有些麻烦

 

 

 

//13.15下面的代码段中发生了多少次析构函数的调用

 

voidfcn(const Sales_item *trans, Sales_item accum)

{

    Sales_itemitem1(*trans), item2(accum);

   if (!item1.same_isbn(item2))return;

   if (item1.avg_price() <= 99)return;

   elseif(item2.avg_price() <= 99)return;

}

 

//accum item1   item2

 

//13.16编写本节中描述的Message类

//13.17为Message类增加与Folder的addMsg和remMsg操作类似的函数。这些函数可以命名为addFldr和remFldr,

//应接受一个指向Folder的指针并将该指针插入到folders。这些函数可为private的,因为它们将仅在Message类的实现中使用

//13.18编写相应的Folder类,该类应保存一个set<Message*>,包含指向Message的元素。

//13.19在Message类中增加save和remove操作。这些操作应接受一个Folder,

//并将该Folder加入到指向这个Message的Folder集中(或从其中删除该Folder)。该操作还必须更新Folder以反映它指向该Message

//这可以通过调用addMsg或remMsg完成。

#include<set>

#include<string>

 

classFolder;

           //Message类定义

classMessage

{

public:

    Message(const std::string &str =""):

      content(str){};

    Message(const Message&);

    Message&operator= (constMessage&);

    ~Message();

 

   void save(Folder&);

   void remove(Folder&);

   void addFldr(Folder*);

   void remFldr(Folder*);

private:

    std::stringcontent;

    std::set<Folder*>folders;

   void put_Msg_in_Folders();

   void remove_Msg_from_Folders();

   

};

           //Folder类定义

classFolder

{

public:

    Folder(){}

    Folder(const Folder&);

    Folder&operator= (constFolder&);

    ~Folder();

   

   void save(Message&);

   void remove(Message&);

   void addMsg(Message*);

   void remMsg(Message*);

private:

    std::set<Message*>messages;

   void put_Fldr_in_Messages();

   void remove_Fldr_from_Messages();

   

};

 

 

               //Message函数定义

   //复制构造函数

Message::Message(const Message& other):

    content(other.content),folders(other.folders)

{

    put_Msg_in_Folders();  

}

   //赋值函数

Message& Message::operator=(constMessage& rhs)

{

   if(&rhs !=this)

    {

        remove_Msg_from_Folders();

        content= rhs.content;

        folders= rhs.folders;

        put_Msg_in_Folders();

    }

   return *this;

}

   //析构函数

Message::~Message()

{

    remove_Msg_from_Folders();

}

   //put_Msg_in_Folders

voidMessage::put_Msg_in_Folders()

{

   for(std::set<Folder*>::const_iteratorcur(folders.begin());

                                    cur!= folders.end(); cur++)

        (*cur)->addMsg(this);

}

   //remove_Msg_from_Folders

voidMessage::remove_Msg_from_Folders()

{

   for(std::set<Folder*>::const_iteratorbeg(folders.begin());

                                    beg!= folders.end(); beg++)

        (*beg)->remMsg(this);

}

 

voidMessage::addFldr(Folder* fldr)//这里不能用const,因为和set容器中的数据类型是关联的

{

    folders.insert(fldr);

}

voidMessage::remFldr(Folder* fldr)

{

    folders.erase(fldr);

}

 

voidMessage::save(Folder& fldr)

{

    addFldr(&fldr);

    fldr.addMsg(this);

}

voidMessage::remove(Folder& fldr)

{

    remFldr(&fldr);

    fldr.remMsg(this);

}

 

               //Folder函数定义

       //复制构造函数

Folder::Folder(constFolder& other):

    messages(other.messages)

{

    put_Fldr_in_Messages();

}

       //赋值函数

Folder& Folder::operator= (constFolder& rhs)

{

   if(&rhs !=this)

    {

        Remove_Fldr_from_Messages();

        messages= rhs.messages;

        put_Fldr_in_Messages();

    }

   return *this;

}

       //析构函数

Folder::~Folder()

{

    remove_Fldr_from_Messages();

}

 

voidFolder::put_Fldr_in_Messages()

{

   for(std::set<Message*>::const_iteratorbeg(messages.begin());

                                        beg!= messages.end(); beg++)

        (*beg)->addFldr(this);

}

voidFolder::remove_Fldr_from_Messages()

{

   for(std::set<Message*>::const_iteratorbeg(messages.begin());

                                        beg!= messages.end(); beg++)

        (*beg)->remFldr(this);

}

voidFolder::addMsg(Message* msg)

{

    messages.insert(msg);

}

voidFolder::remMsg(Message* msg)

{

    messages.erase(msg);

}

voidFolder::save(Message& msg)

{

    addMsg(&msg);

    msg.addFldr(this);

}

voidFolder::remove(Message& msg)

{

    remMsg(&msg);

    msg.remFldr(this);

}

 

 

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

inti = 42;

HasPtr p1(&i, 42);

HasPtr p2 = p1;

cout << p2.get_ptr_val() <<endl;

p1.set_ptr_val(0);

cout << p1.get_ptr_val()<<endl;

//值会变呗。。

 

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

//导致指针悬挂吧

 

 

//13.22什么是使用计数

/*使用计数是复制控制成员中使用的编程计数。将一个计数器与类指向的对象相关联,

用于跟踪该类有多少个对象共享同一指针,创建一个单独类指向共享对象并管理使用计数。

由构造函数设置共享对象的状态并将使用计数置为.每当由复制构造函数或赋值操作符生成一个新副本时,

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

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

*/

 

//13.23什么是智能指针,智能指针类如何与实现普通指针行为的类相区别

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

智能指针类与实现普通指针行为的类的区别在于:智能指针通常接受指向动态分配对象的指针并负责删除该对象。

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

只有在撤销了指向共享对象的最后一个智能指针后,才能删除该对象对象。使用计数是实现只能指针类最常用的方式。

*/

 

//13.24实现你自己的使用计数式HasPtr类的版本

 

classHasPtr;

classU_Ptr{

   friendclass HasPtr;

private:

   int *ptr;

   int num;

    U_Ptr(int *p):ptr(p),num(1){}

    ~U_Ptr(){delete ptr;}

};

 

classHasPtr{

public:

    HasPtr(int *_p,int _val): p(new U_Ptr(_p)), val(_val){}

    HasPtr(const HasPtr& obj): p(obj.p), val(obj.val)

    {p->num++; }

    HasPtr&operator= (constHasPtr&);

    ~HasPtr(){if(--p->num == 0)deletep; }

private:

    U_Ptr*p;

   int val;

};

 

HasPtr& HasPtr::operator= (constHasPtr& obj)

{

    ++obj.p->num;

   if(--p->num)

       delete p;

    p= obj.p;

    val= obj.val; 

   return *this;

}

 

 

 

//13.25什么是值类型

/*所谓值类型,是指具有值语义的类,其特征为:对该类对象进行复制时,会得到一个不同的新副本,对副本所做的改变不会影响原有的对象。*/

 

//13.26实现你自己的值型HasPtr类版本

 

classHasPtr{

public:

    HasPtr(constint &p,int i):

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

    HasPtr(const HasPtr& obj):

        ptr(newint(*obj.ptr)),val(obj.val){}

    HasPtr&operator= (constHasPtr&);

    ~HasPtr(){delete ptr;}

private:

   int *ptr;

   int val;

};

   //这里注意,赋值操作符不需要再重分配空间

HasPtr& HasPtr::operator= (constHasPtr& obj)

{

    *ptr= *obj.ptr;

    val= obj.val;

   return *this;

}

 

//13.27值型HasPtr类定义了所有复制控制成员。描述将会发生什么,如果该类:

//a,定义了复制构造函数和析构函数但没有定义赋值操作符

//b,定义了复制构造函数和赋值操作符但没有定义析构函数

//c,定义了析构函数但没有定义复制构造函数和赋值操作符

 

//a,赋值时指针指向相同

//b,内存泄露

//c,指针悬挂

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值