C++primer练习13.1-13.21

练习13.1

拷贝构造函数是什么?什么时候使用它?

::可以将其理解成对复制已有的去创造新的这个过程的定义,在拷贝初始化和函数返回和参数(不为引用的时候)出现比较频繁,为了不必区分直接初始化和拷贝初始化,拷贝构造函数的参数最好是const的引用,引用很重要,毕竟在定义拷贝构造的参数时,要调用自身会陷入死循环

练习13.2

解释为什么下面的声明是非法的:

Sales_data ::Sales_data(Sales_data rhs)

::引用很重要敲重点,上一题有赘述

练习13.3

当我们拷贝一个StrBlob时,会发生什么?拷贝一个StrBlobPtr呢?

::拷贝一个StrBlob会拷贝shared_ptr指针,StrBlobPtr会拷贝一个weak_ptr和size_t

练习13.4

假定point是一个类类型,它有一个public的拷贝构造函数,指出下面程序片段中哪些地方使用了拷贝构造函数:

Point global;

Point foo_bar(Point arg);1参数非引用

{

Point local =arg,*heap=new Point(global);2、两个初始化均是拷贝初始化

*heap=local;

Point pa[4]={local,*heap};3、列表初始化元素用了拷贝初始化

 return *heap;4、函数返回值非引用即拷贝

}

练习13.5

给定下面的类框架,编写一个拷贝构造函数,拷贝所有成员。你的构造函数应该动态分配一个新的string,并将对象拷贝到ps所指向的位置,而不是拷贝ps本身:

class HasPtr{

public:

  HasPtr(const std::string &s=std::string());

  ps(new std::string(s)),i(0){}

private:

  std::string *ps;

  int i;

};

HasPtr(const HasPtr &s )
{
    ps(new string(*(s.ps)));
    i(s.i);
}

练习13.6

拷贝赋值运算符是什么?什么时候使用它?合成拷贝赋值运算符完成什么工作?什么时候会生成合成拷贝运算符?

::将一个对象的值复制给另一个已存在的对象,合成拷贝运算符会将类内成员分别用其内置或自己的拷贝赋值运算符进行赋值,在没有定义拷贝赋值运算符时系统将自动合成拷贝运算符

练习13.7

当我们将一个StrBlob赋值给另一个StrBlob时,会发生什么?赋值StrBlobPtr呢??

::都将采用合并赋值运算符,会将shared_ptr复制另一个的成员,StrBlobPtr会将weak_ptr复制过去,并赋值size_t值

练习13.8

为练习13.5中的HasPtr类编写赋值运算符。类似拷贝构造函数

HasPtr& HasPtr::operator=(const HasPtr&rhs)
{
     ps(new string(*(rhs.ps)));
    i(s.i);
}

练习13.9

析构函数是什么?合成析构函数完成什么工作?什么时候会生成合成析构函数?

::执行销毁对象,释放资源的函数,合成析构函数释放类的成员,未定义合成析构函数时生成

练习13.10

当一个StrBlob对象销毁时会发生什么?一个StrBlobPtr对象销毁时呢?

::如果data计数减为0的时候释放资源。 销毁对象中的每个成员并且减计数。

练习13.11

为前面练习的HasPtr类添加一个析构函数

~HasPtr() {
    delete ps;
}

练习13.12

在下面的代码片段中会发生几次析构函数调用?

bool fcn(const Sales_data *trans ,Sales_data accum)

{

Sales_data item1(*trans),item2(accum);

return item.isbn() !=item.isbn();

}

::3次

练习13.13

理解拷贝控制成员和构造函数的一个好方法是定义一个简单的类,为该类定义这些成员,每个成员都打印出自己的名字:

struct x{

x(){std::cout<<"x()"<<std::endl:}

x(const x&){std::cout<<"x(const x&)"<<std::endl;}

}

给x添加拷贝赋值运算符和析构函数,并编写一个程序以不同的方式使用x的对象:将它们作为引用或非引用参数传递;动态分配它们;将它们存放在容器中;诸如此类。观察程序的输出,有时编译器可以略过对拷贝构造函数的调用

#include<iostream>
#include<vector>

struct x{

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

x(const x&){std::cout<<"x(const x&)"<<std::endl;}

operator=(const x&){std::cout<<"operator=(const x&)"<<std::endl;}

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

x func(x&a)
{return a;
}
int main()
{

    x tem;

    x tem2(tem);    
    tem2=func(tem);
    tem=tem2;
    auto p=new x(tem);
    std::vector<x> r{tem,tem2};
}

练习13.14

假定numbered是一个类,它有一个默认构造函数,能为每个对象生成一个唯一的序号,保存在名为mysn的数据成员中。假定numbered使用合成的拷贝控制成员,并给定如下函数:

void f(numbered s){cout<<s.mysn<<endl;}

则下面代码输出什么内容?

numbered a,b=a,c=b;

f(a);f(b);f(c);

::输出a.mysn

练习13.15

假定numbered定义了一个拷贝构造函数,能生成一个新的序号。这会改变上一题调用的输出结果吗?如果会改变,为什么?新的输出结果是什么?

::会改变,因为赋值运算符赋给了新对象并且f的参数非引用,会产生拷贝初始化,调用拷贝构造函数,结果都是新的序号各不相同

练习13.16

如果f中的参数是const numbered&,将会怎么样?这会改变输出结果吗,为什么?新的输出结果是什么?

::不会,因为参数为const的引用之后就不会拷贝给形参进行拷贝初始化

练习13.17

分别编写前三题中的表述

struct numbered{
    
    int mysn;
    numbered():mysn(rand()){}

};

void f( numbered d)
{
    std::cout<<d.mysn<<std::endl;
}

int main()
{
    numbered a,b=a,c=b;

f(a);f(b);f(c);
}
#include <iostream>
#include <time.h>
#include <cstdlib> 

struct numbered{
    
    int mysn;
    numbered():mysn(rand()){}
    numbered(numbered&d):mysn(rand()){}
};

void f( numbered d)
{
    std::cout<<d.mysn<<std::endl;
}

int main()
{
    numbered a,b=a,c=b;

f(a);f(b);f(c);
}
#include <iostream>
#include <time.h>
#include <cstdlib> 

struct numbered{
    
    int mysn;
    numbered():mysn(rand()){}
    numbered(numbered&d):mysn(rand()){}
};

void f(const numbered&d)
{
    std::cout<<d.mysn<<std::endl;
}

int main()
{
    numbered a,b=a,c=b;

f(a);f(b);f(c);
}

  练习13.18

定义一个Employee类,它包含雇员的姓名和唯一的雇员证号。为这个类定义默认构造函数,以及接受一个姓名的string的构造函数。每个构造函数应该通过递增一个static成员进行编号

#include <iostream>
#include <time.h>
#include <cstdlib> 


class Employee{
    public:
    std::string name;
    int number;
    static unsigned no;
    Employee()=default;
    Employee(const std::string&s):name(s),number(no++){    }
    
};
unsigned Employee::no=1000;
int main()
{
    Employee a;
    Employee b("lalala"),c("lala");
    std::cout<<a.number<<b.number<<std::endl;
}

练习13.19

你的Employee类需要定义它自己的拷贝控制成员吗?如果需要,为什么?如果不需要为什么?实现你认为需要的拷贝控制成员

::不需要,感觉默认合成的就行

练习13.20

解释我们当拷贝、赋值或销毁TextQuery和queryresult类对象时会发生什么

::改变shared_ptr指针的计数或者销毁

练习13.21

你认为TextQuery和QueryResult需要定义自己版本的拷贝控制成员吗?如果需要,为什么?如果不需要为什么

::不需要,shared_ptr指针的拷贝,合成的操作就能支持想要的效果

 

posted @ 2022-08-12 16:08  yddl  阅读(49)  评论(0编辑  收藏  举报