1. 虚析构函数

基类通常应该定义一个虚析构函数。

class Quote
{public:// virtual destructor needed if a base pointer pointing to a// derived object is deletedvirtual ~Quote() = default;   // dynamic binding for the destructor
};

如果基类的析构函数不是虚函数,则delete一个指向派生类对象的基类指针会产生未定义的结果。

Quote *itemP = new Quote;   // same static and dynamic type
delete itemP;     // destructor for Quote called
itemP = new Bulk_quote;     // static and dynamic types differ
delete itemP;     // destructor for Bulk_quote called

虚析构函数会阻止编译器为类合成移动操作(有析构就有拷贝构造和拷贝赋值,那么编译器就不会合成移到操作了)

2. 合成拷贝控制与继承

基类或派生类的合成拷贝控制成员的行为和其他合成的构造函数、赋值运算符或析构函数类似:对类本身的成员依次进行初始化、赋值或销毁的操作。如果成员是一个对象,还使用对象的初始化、赋值或销毁的操作。

基类没有移到操作那么它的派生类也没有。

2.1 派生类中的删除拷贝控制与基类的关系

● 如果基类中的默认构造函数、拷贝构造函数、拷贝赋值运算符或析构函数是被删除的或者不可访问的函数,则派生类中对应的成员也会是被删除的。因为编译器不能使用基类成员来执行派生类对象中基类部分的构造、赋值或销毁操作。
● 如果基类的析构函数是被删除的或者不可访问的,则派生类中合成的默认和拷贝构造函数也会是被删除的。因为编译器无法销毁派生类对象中的基类部分。
● 编译器不会合成一个被删除的移动操作。当我们使用=default请求一个移动操作时,如果基类中对应的操作是被删除的或者不可访问的,则派生类中的操作也会是被删除的。因为派生类对象中的基类部分不能移动。同样,如果基类的析构函数是被删除的或者不可访问的,则派生类的移动构造函数也会是被删除的。

 class B {public:B();B(const B&) = delete;};class D : public B{ }; void test(){D d;//ok//D d2(d);//error//D d3(std::move(d));//隐式使用D的被删除的拷贝构造函数}

在实际编程中,如果基类没有默认、拷贝或移动构造函数,则一般情况下派生类也不会定义相应的操作。

2.2. 移到操作和继承

因为基类缺少移动操作会阻止编译器为派生类合成自己的移动操作,所以当我们确实需要执行移动操作时,应该首先在基类中进行定义。

 class Quote{public:Quote() = default;Quote(const string& s, double sales_price) :bookNo(s), price(sales_price) {}Quote(const Quote&);//拷贝构造函数Quote& operator=(const Quote&);//拷贝赋值运算符Quote(Quote&&);//移动构造函数Quote& operator=(Quote&&);//移动赋值运算string isbn() const;virtual double net_price(size_t n) const;//虚函数virtual void debug() const;virtual ~Quote() {}//对析构函数进行动态绑定private:string bookNo;protected:double price = 0.0;};ostream& print_total(ostream& os, const Quote& item, size_t n){double ret = item.net_price(n);os << "ISBN:" << item.isbn()<< " #sold: " << n << " total due: " << ret << endl;item.debug();return os;}string Quote::isbn() const{return bookNo;}double Quote::net_price(size_t n) const{return n * price;}void Quote::debug() const{cout << "i am quote:" << bookNo << " " << price << endl;}Quote::Quote(const Quote& q){cout << "hello i am 拷贝构造函数Quote" << endl;bookNo = q.bookNo;price = q.price;}Quote& Quote::operator=(const Quote& q){cout << "hello i am 拷贝赋值运算符Quote" << endl;if (this != &q){bookNo = q.bookNo;price = q.price;}return *this;}Quote::Quote(Quote&& q){cout << "hello i am 移动构造函数Quote" << endl;bookNo = std::move(q.bookNo);price = std::move(q.price);q.bookNo = "";q.price = 0;}Quote& Quote::operator=(Quote&& q){cout << "hello i am 移动赋值运算符Quote" << endl;if (this != &q){bookNo = std::move(q.bookNo);price = std::move(q.price);q.bookNo = "";q.price = 0;}return *this;}void test() {Quote test("cuinan", 100);Quote test1(test);Quote test2;test2 = test;Quote test3(std::move(test));test2 = std::move(test);}

输出结果:
hello i am 拷贝构造函数Quote
hello i am 拷贝赋值运算符Quote
hello i am 移动构造函数Quote
hello i am 移动赋值运算符Quote

【引用】

[1] 代码oopTest.h

C++ Primer 5th笔记(chap 15 OOP)构造函数和拷贝控制相关推荐

  1. 【C++ Priemr | 15】构造函数与拷贝控制

    继承的构造函数 1. 简介: 子类为完成基类初始化,在C++11之前,需要在初始化列表调用基类的构造函数,从而完成构造函数的传递.如果基类拥有多个构造函数,那么子类也需要实现多个与基类构造函数对应的构 ...

  2. C++ Primer 5th笔记(chap 19 特殊工具与技术)union

    1. 定义 联合( union) 是一种特殊的类. 一个 union 可以有多个数据成员, 但是在任意时刻的某个成员赋值之后, 该 union 的其他成员就变成未定义的状态了. 对象的存储空间至少要能 ...

  3. C++ Primer 5th笔记(chap 13 拷贝控制)=default

    可以将拷贝控制成员函数定义为 =default 来显示地要求编译器生成合成版本. class Sales_data{public:Sales_data() = default;Sales_data(c ...

  4. C++ Primer 5th笔记(chap 15 OOP)继承之派生类

    1. 构造函数 每个类控制它自己的成员初始化过程:尽管派生类包含了从基类继承而来的成员,但是派生类不能直接初始化这些成员,而是需要使用基类的构造函数来初始化它们. 派生类对象的基类部分与派生类对象自己 ...

  5. C++ Primer 5th笔记(chap 18 大型程序工具) 多重继承之构造函数、析构函数

    1. 继承的构造函数与多重继承 如果从多个基类中继承了相同的构造函数(即形参列表完全相同),则程序将产生错误 struct Basel {Basel () = default;Basel (const ...

  6. C++ Primer 5th笔记(chap 13 拷贝控制)拷贝构造函数

    1. 拷贝构造函数 如果一个构造函数的第一个参数是自身类类型的引用,且任何额外参数都有默认值,则此构造函数是拷贝构造函数. class Foo{public:Foo();//默认构造函数 (仅在程序员 ...

  7. C++ Primer 5th笔记(chap 16 模板和泛型编程)类模板特例化

    1. 定义一个特例化版本, 模板参数为 Sales data // 打开std 命名空间, 以便特例化 std::hash namespace std {template struct hash< ...

  8. C++ Primer 5th笔记(chap 13 拷贝控制)移动构造和移动赋值

    1. 移动构造函数和移动赋值运算符 一般来说,拷贝一个资源会导致一些额外的开销.在这种拷贝并非必要的情况下,定义了移动构造函数和移动赋值运算符的类就可以避免此问题. eg. StrVec::StrVe ...

  9. C++ Primer 5th笔记(chap 13 拷贝控制)合成的移动操作

    1. 出现条件 只有当一个类没有定义任何自己版本的拷贝控制成员,且类的每个非 static 数据成员都可以移动,编译器才会为它合成构造函数或移动赋值运算符. struc X{int i;std::st ...

最新文章

  1. ElectronOCR:基于Electron+React+Tesseract的MACOS下的OCR工具
  2. 求 1 到 n 的所有数的约数和
  3. exit()函数详解与Exit() 和 Return() 的区别
  4. VC++基于APR实现禁止某个业务(开发行为控制软件用得着,例如上班禁止上QQ)...
  5. Mysql 替换字段的一部分内容
  6. 《JavaScript高级程序设计》chapter 1: javascript 简介
  7. mysql 换服务器_更换MYSQL后数据库连接问题
  8. 【视频】Vue作者分享:Vue 3.0 进展
  9. 微型计算机系统的工作过程是不断地,微型计算机原理及应用基本学习要求2017-2(1)...
  10. ASP.NET MVC的最佳日志记录库
  11. 集成学习—GBDT原理理解
  12. 行存储索引改换成列存储索引_列存储索引增强功能–数据压缩,估计和节省
  13. 联想ts250进bios_联想Think TS250/TS550安装server 2008 R2/2012系统教程【一】
  14. 仓储管理毕业论文【含matlab优化算法】
  15. android免费图标_20个免费和高质量的Android图标集—最佳
  16. ssm框架体检管理系统源码+文档
  17. html页面中中文转英文插件,iText 7 的htmlToPdf插件支持转换中文
  18. 使用a标签下载文件而不是直接打开
  19. (五)、JAVA基于OPENXML的word文档插入、合并、替换操作系列之word文件合并[支持多文件]
  20. 一、jSP简介(前置知识)

热门文章

  1. jQuery-点击按钮实现回到顶部的两种方式
  2. Android --- layout_marginStart和layout_marginEnd的详细讲解
  3. php 数组交集函数,PHP array_intersect_uassoc 函数
  4. 用html标记语言,HTML标记语言——引用
  5. java猜数字游戏应用程序_猜数字游戏的Java小程序
  6. 电气接线+线号管正确方向=电工接线好习惯!你有吗?
  7. 读懂 | 路由器简史
  8. java不可编辑的文本框_如何使编辑文本不可编辑,但在JAVA中可点击
  9. 成功解决ValueError: Could not interpret input day
  10. Paper之BigGAN:ICLR 2019最新论文《LARGE SCALE GAN TRAINING FOR HIGH FIDELITY NATURAL IMAGE SYNTHESIS》(未完待续)