C++Prime 第十三章 前30题
练习13.1
拷贝构造函数:通过拷贝对象的方式创建一个新对象.满足以下条件:本身是构造函数,第一个参数必定是自身类类型的引用,且任何额外参数都有默认值. 使用:"=";函数非引用形参;非引用返回值;用花括号初始化一个数组中的元素或者一个聚合类中的成员;某些类类型会对他们所分配的对象使用拷贝初始化.
练习13.2
拷贝构造函数第一个参数必须是对自身类类型的引用,不然会陷入无限的递归调用中. 本题,如定义Sales_data a = b; 则相当于 a.Sales_data(b);将实参b传给了形参rhs. 则相当于 rhs.Sales_data(b); 再次将实参b传给了形参rhs,无限循环.
练习13.3
共享指针引用数加一,弱指针的复制不会影响引用计数.
练习13.4
除了*heap= local 使用的拷贝赋值运算符外,其余均是使用的拷贝构造函数.
练习13.5
HasPtr(const HasPtr
& hp
)
{
HasPtr tmp
;
tmp
.ps
= new string(hp
.ps
);
tmp
.i
= hp
.i
;
return tmp
;
}
练习13.6
拷贝赋值运算符:本质是成员函数,是一个重载的赋值运算符,左侧是隐含的this指针,右侧是指向类类型的对象,函数返回左侧参数的引用. 赋值的时候使用. 合成拷贝赋值运算符:对于某些类,禁止该类型对象的赋值,一般情况是:将右侧运算对象的每个非static成员赋值给左侧运算对象的相应成员. 当类未定义自己的拷贝赋值运算符时,会生成合成的拷贝赋值运算符.
练习13.7
会赋值,区别是共享指针的赋值会使引用计数++,而弱指针不会增加引用计数.
练习13.8
HasPtr
& operator=(const HasPtr
& hp
)
{
delete ps
;
ps
= new string(hp
.ps
);
i
= hp
.i
;
return *this;
}
练习13.9
析构函数:是类的一个成员函数,其名字由波浪线加类名组成,没有返回值也不接受参数,会释放对象使用的资源,并销毁对象的非static数据成员. 合成析构函数的工作:某些类用来阻止该类型的对象被销毁,如果不是这种情况,函数体就为空. 未定义自己的析构函数时,编译器会合成默认的析构函数.
练习13.10
StrBlob:所有成员被销毁,共享指针引用计数–,如果为0,则销毁共享指针所指对象. StrBlobStr:所有成员被销毁.
练习13.11
class HasPtr;
~HasPtr()
{
delete ps
;
}
练习13.12
三次.函数离开作用域时,accum形参被销毁,局部对象item1和item2被销毁.
练习13.13
struct X
{
X() { cout
<< "X()" << endl
; }
X(const X
&) { cout
<< "X(const X&)" << endl
; }
X
& operator=(const X
&) { cout
<< "X& operator=(const X&)"; }
~X() { cout
<< "~X()"; }
};
练习13.14
全部输出同样的序号.所以这种情况必须使用自定义的赋值构造函数和拷贝构造函数.
练习13.15
会.调用了拷贝构造函数.但是要注意,传给f时还要调用拷贝构造,所以最后结果也不是输出a,b,c的序号.
练习13.16
会改变.此时传给f的参数是引用,那么就不会调用拷贝构造函数,会直接输出a,b,c的序号.
练习13.17
不用编写了,对了.
练习13.18
#pragma once
#include <iostream>
using std
::string
;
class Employee
{
public:
public:
Employee() = default;
Employee(const std
::string
& name
) :m_name(name
) ,m_no(++id
){}
private:
std
::string m_name
;
int m_no
= ++id
;
static int id
;
friend std
::ostream
& operator<<(std
::ostream
& os
, const Employee
& e
)
{
os
<< e
.m_name
<< " " << e
.m_no
;
return os
;
}
};
练习13.19
需要删除版的,编译器合成的拷贝控制成员会出错.
#pragma once
#include <iostream>
using std
::string
;
class Employee
{
public:
public:
Employee() = default;
Employee(const std
::string
& name
) :m_name(name
) ,m_no(++id
){}
Employee(const Employee
&) = delete;
Employee
& operator=(const Employee
&) = delete;
private:
std
::string m_name
;
int m_no
= ++id
;
static int id
;
friend std
::ostream
& operator<<(std
::ostream
& os
, const Employee
& e
)
{
os
<< e
.m_name
<< " " << e
.m_no
;
return os
;
}
};
练习13.20
对TextQuery: 拷贝:拷贝所有成员,共享指针引用计数加一 赋值:同上 销毁:销毁所有成员,共享指针引用计数减一 对QueryResult: 同上.
练习13.21
完全不需要,合成的就足够完成所有工作.
练习13.22
HasPtr(const HasPtr
& hp
)
{
HasPtr tmp
;
tmp
.ps
= new string(hp
.ps
);
tmp
.i
= hp
.i
;
return tmp
;
}
#pragma once
#include <iostream>
using std
::string
;
class HasPtr
{
public:
HasPtr(const HasPtr
&);
HasPtr(const std
::string
& s
= string()) :ps(new string(s
)), i(0) {}
HasPtr
& operator=(const HasPtr
&);
~HasPtr() { delete ps
; }
private:
string
*ps
;
int i
;
};
#include "HasPtr.h"
HasPtr
::HasPtr(const HasPtr
& hp
)
{
ps
= new string(*(hp
.ps
));
i
= hp
.i
;
}
HasPtr
& HasPtr
::operator=(const HasPtr
& hp
)
{
auto newp
= new string(*hp
.ps
);
delete ps
;
ps
= newp
;
i
= hp
.i
;
return *this;
}
练习13.23
yes,啊sir
练习13.24
未定义析构: 那么每个对象的ps所指向的内存都不会背释放,造成资源泄露. 未定义拷贝控制函数:那么全部是浅复制,造成所有类对象指向同一块内存,一旦某个对象释放掉这块内存,所有对象的ps指针统统变成野指针.
练习13.25
练习13.26
略
练习13.27
书上代码比着敲一遍
练习13.28
class TreeNode {
public:
TreeNode(string v
= "", int c
= 0, TreeNode
* l
= nullptr, TreeNode
* r
= nullptr)
:value(v
), count(c
), left(l
), right(r
) { }
TreeNode(const TreeNode
& node
);
TreeNode
& operator=(const TreeNode
& node
);
~TreeNode();
private:
std
::string value
;
int count
;
TreeNode
* left
;
TreeNode
* right
;
};
TreeNode
::TreeNode(const TreeNode
& node
)
{
value
= node
.value
;
count
= node
.count
;
left
= new TreeNode(*node
.left
);
right
= new TreeNode(*node
.right
);
}
TreeNode
& TreeNode
::operator=(const TreeNode
& node
)
{
auto leftp
= new TreeNode(*node
.left
);
auto rightp
= new TreeNode(*node
.right
);
delete left
;
delete right
;
left
= leftp
;
right
= rightp
;
count
= node
.count
;
value
= node
.value
;
return *this;
}
TreeNode
::~TreeNode()
{
delete left
;
delete right
;
}
练习13.29
swap(HasPtr&,HasPtr&)中的swap是std::swap,相当于函数内调用了一个其他的函数,自然不会递归调用.
练习13.30
inline
void swap(HasPtr
& h1
, HasPtr
& h2
)
{
std
::cout
<< "Swap()""被执行了" << std
::endl
;
using std
::swap
;
swap(h1
.ps
, h2
.ps
);
swap(h1
.i
, h2
.i
);
}
测试:
HasPtr h1
, h2
;
swap(h1
, h2
);