C++primer 阅读点滴记录(一)
第十三章 复制控制:(copy control)
复制构造函数(copy constructor)
复制操作符(assignment operator)
ps: 什么时候需要显示的定义复制控制操作:类具有指针成员,一般情况使用默认的复制控制
有的类 需要禁止复制构造函数, iostream类就不允许复制
类必须显示的声明其复制构造函数为private
| 最佳实践: | 一般来说,最好显示或隐式定义默认构造函数和复制构造函数,只有不存在其他构造函数是才合成默认构造函数,如果定义了复制构造函数,也必须定义默认构造函数 |
//示例代码:
//copy constructor :
Sales_item(const Sales_item& orig):
isbn(orig.isbn),
units_sold(orig.units_sold),
revenue(orig.revenue){}
//assignment operator:
Sales_item& operator=(const Sales_items& rhs) Sales_item& Sales_item::operator=(const Sales_item& rhs){
isbn = rhs.isbn;
units_sold = rhs.units_sold;
revenue = rhs.revenue;
return *this;
}
| 注解: | 实际上,应该将复制和赋值两个操作看作一个单元。 如果需要其中一个,我们几乎也肯定需要另一个。 |
13.3 析构函数(destructor)
何时调用析构函数:
/*
* 撤销类对象时会自动调用析构函数
* 动态分配的对象只有在指向该对象的指针被删除时才撤销
*/
void destructor_test(){
Sales_item* p = new Sales_item;
{//new scope
Sales_item item(*p);//copy constructor copies *p into item
delete p;//destructor called on object pointed to by p
}//exit local scope; destructor called on item
}
| 提示: | 如果类需要析构函数,则它也需要赋值操作符和复制构造函数,这是一个有用的经验法则。这个规则常称为三法则(rule of three),指的是如果需要析构函数,则需要所有这三个幅值控制成员。 |
| 注解: | 撤销内置类型成员或复合类型的成员没什么影响。 尤其是,合成析构函数并不删除指针成员所指向的对象。(ps:所以 有指针对象成员的类 需要析构函数,需要复制构造函数 赋值操作符) |
消息实例 演示复制控制
#ifndef MESSAGE_H
#define MESSAGE_H
#pragma once
#include <string>
#include <iostream>
#include <set> using namespace std; class Message; class Folder{
public:
Folder(const string& s):folder_name(s){}
Folder(const Folder&);
Folder& operator=(const Folder&);
~Folder(); void save(Message&);
void remove(Message&); void addMsg(Message*);
void remMsg(Message*);
private:
set<Message*> messages;
string folder_name; void put_Fldr_in_Message(const set<Message*>&);
void remove_Fldr_from_Message();
}; class Message
{
public:
Message(const string& str=""):contents(str){}
Message(const Message&);//复制构造函数
Message& operator=(const Message&);//赋值操作符
~Message(); void save(Folder&);
void remove(Folder&); void addFldr(Folder*);
void remFldr(Folder*);
private:
string contents; //actual message text
set<Folder*> folders;//folders that have this message
void put_Msg_in_Folder(const set<Folder*>&);
void remove_Msg_from_Folders();
}; #endif // !MESSAGE_H
#include "stdafx.h"
#include "Message.h" Message::Message(const Message& m):contents(m.contents),folders(m.folders)
{
put_Msg_in_Folder(folders);
} void Message::put_Msg_in_Folder(const set<Folder*>& rhs){
for(set<Folder*>::const_iterator beg = rhs.begin();
beg != rhs.end();++beg)
(*beg)->addMsg(this);
}
Message& Message::operator=(const Message& rhs){
if(&rhs != this){
remove_Msg_from_Folders();
contents = rhs.contents;
folders = rhs.folders;
put_Msg_in_Folder(rhs.folders);
}
return *this;
}
void Message::remove_Msg_from_Folders(){
for(set<Folder*>::const_iterator beg = folders.begin();
beg != folders.end();++beg)
(*beg)->remMsg(this);
} Message::~Message()
{
remove_Msg_from_Folders();
} void Message::addFldr(Folder* f){
folders.insert(f);
} void Message::remFldr(Folder* f){
folders.erase(f);
} void Message::save(Folder& fldr){
addFldr(&fldr);
fldr.addMsg(this);
} void Message::remove(Folder& fldr){
remFldr(&fldr);
fldr.remMsg(this);
} //Folder
Folder::Folder(const Folder& f):messages(f.messages),folder_name(f.folder_name){
put_Fldr_in_Message(f.messages);
} void Folder::put_Fldr_in_Message(const set<Message*>& rhs){
for(set<Message*>::const_iterator beg = rhs.begin();
beg != rhs.end(); ++beg)
(*beg)->addFldr(this);
} void Folder::remove_Fldr_from_Message(){
for (set<Message*>::const_iterator beg =messages.begin();
beg != messages.end(); ++beg)
(*beg)->remFldr(this);
} Folder& Folder::operator=(const Folder& rhs){
if(&rhs != this){
messages = rhs.messages;
folder_name = rhs.folder_name;
put_Fldr_in_Message(messages);
}
return *this;
} Folder::~Folder(){
remove_Fldr_from_Message();
} void Folder::save(Message& msg){
addMsg(&msg);
msg.addFldr(this);
} void Folder::remove(Message& msg){
remMsg(&msg);
msg.remFldr(this);
} void Folder::addMsg(Message* msg){
messages.insert(msg);
} void Folder::remMsg(Message* msg){
messages.erase(msg);
}
C++primer 阅读点滴记录(一)的更多相关文章
- C++primer 阅读点滴记录(三)
14章 操作符重载和转换 重载操作符是具有特殊名称的函数:保留字operator后接需要定义的操作符符号. 1.重载的操作符名: + – * / % ^ & | ~ ! , = < & ...
- C++primer 阅读点滴记录(二)
智能指针(smart point) 除了增加功能外,其行为像普通指针一样. 一般通过使用计数(use count)或引用计数(reference count)实现智能指针,防止出现指针 ...
- C++ Primer 阅读笔记:迭代器和容器 小结
原创 by zoe.zhang 0.写在前面的话 我是在2011年学的C++,但是那一年恰好是C++11新标准的一年,但是大学上学的C++还是基于C++98的风格的,使用的编译器也是VC6.0,啊, ...
- 《JavaScript高级程序设计(第3版)》阅读总结记录第一章之JavaScript简介
前言: 为什么会想到把<JavaScript 高级程序设计(第 3 版)>总结记录呢,之前写过一篇博客,研究的轮播效果,后来又去看了<JavaScript 高级程序设计(第3版)&g ...
- [踏得网]HTML5在线教程阅读进度记录
2017年1月3日18:12:19http://techbrood.com/h5b2a?p=html-canvas-states 2017年1月3日17:10:11http://techbrood.c ...
- android 点滴记录 ICCID IMSI IMEI MEID 关系 和 区别,相关参数在什么情况下可以获取...
1:ICCID:Integrate circuit card identity 集成电路卡识别码(固化在手机SIM卡中) ICCID为IC卡的唯一识别号码,共有20位数字组成,其编码格式为:XXXXX ...
- android 点滴记录
1.AndroidM环境下,在framework层添加代码会对jar包的package name进行检查,并提示”unknown package name of class file”怎么解决? 产生 ...
- MiniProfiler使用点滴记录-2017年6月23日11:08:23
1.看似针对同样一段查询表ef达式,重复执行却没有被记录下来.其实这是正常情况,因为ef并没有重复去执行 相同sql查询. 2.MiniProfiler结合MVC过滤器进行 拦截记录Sql,示例代码: ...
- Git点滴记录
合并多个commit记录 假设我们当前有三个commit信息,现在要将commit hash为 23f92c 和 409978 合并 //git rebase -i HEAD~3 那么我们可以使用 r ...
随机推荐
- AdapterView的相关知识。
AdapterView集成自ViewGroup,他的主要子类有AbsListView(Listview,GridView),AbsSpinner(Spinner,Gallery). AdapterVi ...
- Linux下配置xampp
How do I install XAMPP?Choose your flavor for your linux OS, the 32-bit or 64-bit version. Change th ...
- ARM开发板挂载U盘
ARM开发板运行Linux系统后,插入U盘,通过串口打印系统识别到U盘如下: 系统识别U盘盘符为sda4 那么需要挂载后才能操作U盘:挂载命令 mount -t vfat /dev/sda4 /mnt ...
- JavaScript对象的创建之使用json格式定义
json: javascript simple object notation. json就是js的对象,但是它省去了xml中的标签,而是通过{}来完成对象的说明. 定义对象 var person = ...
- windows Phone 浏览器窗口的尺寸
移动设备的屏幕一般都比PC小很多,移动设备的浏览器会将一个较大的 “虚拟” 窗口映射到移动设备的屏幕上,然后按一定的比例(3:1或2:1)进行缩放.也就是说当我们加载一个普通网页的时候,移动浏览器 ...
- unity区分点击在3D物体还是2D UI上
当场景中的3D物体需要响应点击,但同时有UI显示时,存在判断点击是在3D物体上还是UI上的问题,办法如下: 1. 射线检测所有2D 3D物体,有2D物体被检测到时表明当前有UI.但无论Physics2 ...
- NAT学习笔记
NAT介绍 NAT, 全称网络地址转换(Network Address Translation),是一种在IP封包通过路由器或防火墙时重写来源IP地址或目的IP地址的技术. NAT的分类及介绍 NAT ...
- Markdown 编辑器语法指南
基本技巧 代码 如果你只想高亮语句中的某个函数名或关键字,可以使用 `function_name()` 实现 通常编辑器根据代码片段适配合适的高亮方法,但你也可以用 ``` 包裹一段代码,并指定一种语 ...
- EF调用存储过程遇到的问题
注意 实体类Statistics的字段名和存储过程返回集合的列名要相同才行
- JS判断手机浏览器
<script type="text/javascript"> /* * 智能机浏览器版本信息: * */ varbrowser={ versions:function ...