【C++ Primer 第13章】1. 拷贝控制、赋值和销毁
拷贝控制、赋值和销毁
- 如果一个构造函数的第一个参数是自身类的引用,且额外的参数都有默认值,则此构造函数是拷贝控制函数(拷贝构造函数不应该是explicit的)。
- 如果我们没有为一个类定义拷贝构造函数,编译器会为我们定义一个,与合成默认构造函数不同, 即使我们定义了其他构造函数,编译器也会为我们合成一个拷贝构造函数。
class Sales_data
{
public:
Sales_data(const Sales_data&);
private:
string bookNo;
int units_sold = ;
double revenue = 0.0;
}; Sales_data::Sales_data(const Sales_data &rhs):
bookNo(rhs.bookNo), //ISBN号
units_sold(rhs.units_sold), //销量
revenue(rhs.revenue) //总销售收入
{}
析构函数
- 当一个类定义自己的析构函数时,编译器会为它定义一个合成析构函数。
练习参考答案
13.13
#include<iostream>
#include<string>
#include<vector>
using namespace std; struct X
{
X() { cout << "默认构造函数X()" << endl; }
X(const X&) { cout << "拷贝构造函数 X(const X&)" << endl; }
X& operator=(const X &rhs) { cout << "拷贝赋值运算符=(const X&)" << endl; return *this; }
~X() { cout << "析构函数 ~()" << endl; }
}; void f1(X x)
{} void f2(X &x)
{} int main()
{
cout << "局部变量" << endl;
X x;
cout << endl; cout << "非引用参数传递:" << endl;
f1(x);
cout << endl; cout << "引用参数传递" << endl;
f2(x);
cout << endl; cout << "动态内存:" << endl;
X *px = new X(x);
cout << endl; cout << "添加到容器中:" << endl;
vector<X> vx;
vx.push_back(x);
cout << endl; cout << "释放动态内存" << endl;
delete px;
cout << endl; cout << "间接初始化和赋值:" << endl;
X y = x;
y = x;
cout << endl; cout << "程序结束" << endl;
return ;
}
运行结果:

三五法则
- 如果一个类需要自定义析构函数,几乎可以肯定它也需要自定义拷贝赋值运算符和拷贝构造函数。
- 如果一个人类需要一个拷贝构造函数,几乎可以肯定它也需要一个拷贝赋值运算符。
- 如果一个类需要一个拷贝赋值运算符,几乎可以肯定它也需要一个拷贝构造函数。
练习参考答案
//13.14: 0 0 0 //13.15: 3 4 5 //13.16: 0 1 2 #include<iostream>
using namespace std; class numbered
{
private:
static int seq;
public:
numbered() { mysn = seq++; }
numbered(numbered &n) { mysn = seq++; }
int mysn;
}; int numbered::seq = 0; void f(numbered s)
{
cout << s.mysn << endl;
} int main(int argc, char **argv)
{
numbered a, b = a, c = b;
f(a);
f(b);
f(c);
return 0;
}
使用=default
- 我们可以通过将拷贝控制成员定义为=default来显式地要求编译器生成合成的版本。
class Sales_data
{
public:
//拷贝控制成员; 使用default
Sales_data() = default;
Sales_data(const Sales_data &) = default;
Sales_data& operator=(const Sales_data &);
~Sales_data() {} = default;
//其他成员的定义,如前
}
Sales_data& Sales_data::operator=(const Sales_data &) = default;
阻止拷贝
如果一个类有数据成员不能默认构造、拷贝、复制和销毁,则对应的成员函数将被定义为删除的。规则引申如下:
- 如果类的某个成员的析构函数时删除的或不可访问的,则类的合成析构函数被定义为删除的;同时类的默认构造函数是删除的;同时类的合成拷贝构造函数也被定义为删除的。(析构函数被定义为删除的,则不能定义该类型的变量。)
- 如果类的某个成员的拷贝构造函数是删除的或不可访问的,则类的合成拷贝构造函数被定义为删除的;
- 如果类的某个成员的拷贝赋值运算符是删除的或不可访问的,或类有一个const的或引用成员,则类的合成拷贝赋值运算符被定义为删除的;
- 如果类有一个引用成员,它没有类内初始化器,或是类有一个const成员,没有类内初始化器且其类型未显式定义默认构造函数,则该类的默认构造函数是删除的。
练习参考答案
【练习13.5】
class HasPtr
{
public:
HasPtr(const string &s = string()): ps(new string(s)), i() {}
HasPtr(const HasPtr &rhs): ps( new string(*rhs.ps)), i(rhs.i) {}
private:
string *ps;
int i;
}
【练习13.8】
class HasPtr
{
public:
HasPtr(const string &s = string()): ps(new string(s)), i() {}
HasPtr(const HasPtr &rhs): ps( new string(*rhs.ps)), i(rhs.i) {} HasPtr operator=(const HasPtr &rhs);
private:
string *ps;
int i;
} HasPtr HasPtr::operator=(const HasPtr &rhs)
{
ps = new string(*rhs.ps);
i = rhs.i;
return *this;
【C++ Primer 第13章】1. 拷贝控制、赋值和销毁的更多相关文章
- [C++ Primer] : 第13章: 拷贝控制
拷贝, 赋值与销毁 当定义一个类时, 我们显示地或隐式地指定在此类型的对象拷贝, 移动, 赋值和销毁时做什么. 一个类通过定义5种特殊的成员函数来控制这些操作, 包括: 拷贝构造函数, 拷贝赋值运算符 ...
- 【C++ Primer 第13章】2. 拷贝控制和资源管理
拷贝控制和资源管理 • 类的行为像一个值.意味着它应该有自己的状态,当我们拷贝一个像值得对象时,副本和原对象是完全独立的,改变副本不会对原对象有任何影响. • 行为像指针的类则共享状态.当我们拷贝一个 ...
- C++ Primer : 第十三章 : 拷贝控制之拷贝、赋值与销毁
拷贝构造函数 一个构造函数的第一个参数是自身类类型的引用,额外的参数(如果有)都有默认值,那么这个构造函数是拷贝构造函数.拷贝构造函数的第一个参数必须是一个引用类型. 合成的拷贝构造函数 在我们没 ...
- 【C++ Primer | 15】构造函数与拷贝控制
合成拷贝控制与继承 #include <iostream> using namespace std; class Base { public: Base() { cout << ...
- 【C++ Primer 第13章】3. 交换操作
交换操作 class HasPtr { friend void swap(HasPtr &rhs, HasPtr &yhs); //其他成员定义 }; void swap(HasPtr ...
- 【C++ Primer 第13章】6.对象移动
右值引用 左值和右值 (1)两者区别: ①左值:能对表达式取地址.或具名对象/变量.一般指表达式结束后依然存在的持久对象. ②右值:不能对表达式取地址,或匿名对象.一般指表达式结束就不再存在的临时对象 ...
- 【C++ Primer 第13章】5. 动态内存管理类
StrVec类的设计 [题目描述]:我们将实现标准库vector类的一个简化版本,我们所做的一个简化是不使用模板,我们类只用于string,因此,它被命名为StrVec. #include<io ...
- 《C++ Primer》笔记 第13章 拷贝控制
拷贝和移动构造函数定义了当用同类型的另一个对象初始化本对象时做什么.拷贝和移动赋值运算符定义了将一个对象赋予同类型的另一个对象时做什么.析构函数定义了当此类型对象销毁时做什么.我们称这些操作为拷贝控制 ...
- 【c++ Prime 学习笔记】第13章 拷贝控制
定义一个类时,可显式或隐式的指定在此类型对象上拷贝.移动.赋值.销毁时做什么.通过5种成员函数实现拷贝控制操作: 拷贝构造函数:用同类型的另一个对象初始化本对象时做什么(拷贝初始化) 拷贝赋值算符:将 ...
随机推荐
- Debian 为firefox安装flash插件 以及 音频驱动
1. flash下载地址:http://get.adobe.com/cn/flashplayer/ lv@lv:~/Downloads$ tar -zxvf flash_player_npapi_li ...
- Android 正则表达式验证手机号码
方案一:比较精准的判断手机段位,但是随着手机号段的增多要不断的修改正则 public boolean isPhoneNumber1(String phone) { String regExp = &q ...
- Gradle的使用
⒈下载 点击此处 ⒉安装 1.解压 2.添加环境变量GRADLE_HOME 指向解压缩文件的磁盘地址 3.PATH环境变量添加%GRADLE_HOME%\bin ⒊使用阿里云仓库 repositori ...
- 20165231 2017-2018-2 《Java程序设计》第5周学习总结
教材学习内容总结 第七章 内部类 在一个类中声明另一个类,这样的类称作内部类,而包含内部类的类成为内部类的外嵌类. 内部类的类体中不可以声明类变量和类方法.外嵌类的类体中可以用内部类声明对象,作为外嵌 ...
- 【转】shell速查表
shell速查表 转自:https://www.jianshu.com/p/a98a334bfb25 1. 变量 #!/bin/bash msg="hello world" ech ...
- 设计模式C++学习笔记之二(Proxy代理模式)
代理,一看名字就知道这只是个中介而已,真实的执行者在代理的后面呢.cbf4life在他的书里提的例子也很有趣,更详细的内容及说明可以参考原作者博客:cbf4life.cnblogs.com.现在贴 ...
- java二分查找
二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好:其缺点是要求待查表为有序表,且插入删除困难.因此,折半查找方法适用于不经常变动而查找频繁的有序列表.首先,假设表中元素是按升序排列,将表 ...
- Directory 中user Var 如何添加到通道变量中?
FS默认的配置,ACL 是 拒绝的,只能通过 Digest 的方式进行认证,一旦认证成功之后,directory 中的 var 就能在通道中通过${} 的方式获取到. 如果ACL 认证通过 ,就直接走 ...
- 使用layui框架做分页
第一步引用两个文件: <link href="layui-v2.2.5/layui-v2.2.5/layui/css/layui.css" rel="stylesh ...
- 帮你彻底搞懂JS中的prototype、__proto__与constructor(图解)
作为一名前端工程师,必须搞懂JS中的prototype.__proto__与constructor属性,相信很多初学者对这些属性存在许多困惑,容易把它们混淆,本文旨在帮助大家理清它们之间的关系并彻底搞 ...