c++ 拷贝构造函数、拷贝运算符、析构函数
拷贝构造函数、拷贝运算符、析构函数
拷贝构造函数、拷贝运算符、析构函数
定义行为像值的类
class HasPtr{
public:
HasPtr(const string &s = string()):ps(new string(s)), i(0) {
cout<<"HasPtr(const string &s = string())"<<endl;
}
HasPtr(const HasPtr &hp) :ps(new string(*hp.ps)), i(hp.i) {
cout<<"HasPtr(const HasPtr &hp)"<<endl;
}
HasPtr &operator=(const HasPtr &hp) {
auto tmp = new string(*hp.ps); // 右侧对象拷贝到临时变量,考虑自己拷贝自己的情况。
delete ps; // 析构左侧对象
ps = tmp;
i = hp.i;
cout<<"HasPtr &operator="<<endl;
return *this;
}
HasPtr testCopy(HasPtr hp) {
return hp;
}
HasPtr &testCopy1(HasPtr &hp) {
return hp;
}
~HasPtr() {
cout<<"~HasPtr()"<<endl;
}
void print() {
cout<<*ps<<endl;
}
void setPs(const string &str) {
*ps = str;
}
private:
string *ps;
int i;
};
测试代码
HasPtr hp("hello"); // 调用构造函数,输出HasPtr(const string &s = string())
HasPtr hp1 = hp; // 调用拷贝构造函数,输出HasPtr(const HasPtr &hp)
HasPtr hp2; // 调用构造函数,输出HasPtr(const string &s = string())
hp2 = hp; // 调用拷贝运算符函数,输出HasPtr &operator=
hp1.setPs("word"); // 构造函数、拷贝构造函数、拷贝赋值运算符函数都为ps分配了新空间
hp.print(); // 所以hp、hp1、hp2的ps指针指向的空间不一样,修改一个的值其他的不变。
hp1.print(); // 输出word,由setPs函数修改
hp2.print(); // 输出hello,值从hp拷贝过来,空间是新分配的。
// 实参初始化形参要调用一次拷贝构造函数,形参初始化返回的临时变量也要调用一次拷贝构造函数,
hp.testCopy(hp1); // 形参和临时变量在函数结束时时要销毁,调用两次析构函数。
hp.testCopy1(hp1); // 都是引用初始化,不需要调用拷贝构造函数。
HasPtr *hp_ptr = new HasPtr; // 调用构造函数
vector<HasPtr> vec; // 调用vector的默认构造函数。
vec.push_back(hp); // 调用拷贝构造函数
// 接下来要销毁hp,hp1,hp2和vector中的HasPtr的元素,要调用4次析构函数,但是hp_ptr指向的空间不会被销毁。

定义行为像指针的类
class HasPtr{
public:
// 构造函数,为指针指向分配空间(整个类也只在这个地方分配空间),use初始化为1
HasPtr(const string &s = string()):ps(new string(s)), i(0) ,use(new size_t(1)){
cout<<"HasPtr(const string &s = string())-->use"<<*use<<endl;
}
// 拷贝构造函数,只拷贝指针,use值递增
HasPtr(const HasPtr &hp) :ps(new string(*hp.ps)), i(hp.i) ,use(hp.use){
++*use;
cout<<"HasPtr(const HasPtr &hp)-->use"<<*use<<endl;
}
// 拷贝赋值运算符,左侧use递减,当use为0,释放左侧指针指向空间,拷贝右侧数据和指针到左侧对象,use递增。
HasPtr &operator=(const HasPtr &hp) {
if(--*use == 0) {
delete ps;
delete use;
}
++*hp.use;
ps = hp.ps;
use = hp.use;
i = hp.i;
cout<<"HasPtr &operator=-->use"<<*use<<endl;
return *this;
}
HasPtr testCopy(HasPtr hp) {
return hp;
}
HasPtr &testCopy1(HasPtr &hp) {
return hp;
}
// 析构函数,递减use,当use为0,释放指针指向空间。
~HasPtr() {
if(--*use == 0){
delete ps;
delete use;
}
cout<<"~HasPtr()-->use"<<*use<<endl;
}
void print() {
cout<<*ps<<endl;
}
void setPs(const string &str) {
*ps = str;
}
private:
string *ps; // 共享,只有构造函数分配,最后一次析构函数销毁
int i; // 每个对象独享,每次构造函数、拷贝构造函数、拷贝运算符都分配,每次析构都销毁
size_t *use; // 共享,只有构造函数分配,最后一次析构函数销毁
};
测试程序
HasPtr hp("hello"); // 调用构造函数,输出HasPtr(const string &s = string())
HasPtr hp1 = hp; // 调用拷贝构造函数,输出HasPtr(const HasPtr &hp)
HasPtr hp2; // 调用构造函数,输出HasPtr(const string &s = string())
hp2 = hp; // 调用拷贝运算符函数,输出HasPtr &operator=
hp1.setPs("word"); // 拷贝构造函数、拷贝赋值运算符不为指针ps和use分配新空间
hp.print(); // 所以hp、hp1、hp2的ps指针指向相同的空间,修改一个的值其他的也变。
hp1.print(); // 输出word,由setPs函数修改
hp2.print(); // 输出word,由setPs函数修改
// 实参初始化形参要调用一次拷贝构造函数,形参初始化返回的临时变量也要调用一次拷贝构造函数,
hp.testCopy(hp1); // 形参和临时变量在函数结束时时要销毁,调用两次析构函数。
hp.testCopy1(hp1); // 都是引用初始化,不需要调用拷贝构造函数。
HasPtr *hp_ptr = new HasPtr; // 调用构造函数
vector<HasPtr> vec; // 调用vector的默认构造函数。
vec.push_back(hp); // 调用拷贝构造函数
// 接下来要销毁hp,hp1,hp2和vector中的HasPtr的元素,要调用4次析构函数,只有最后一次调用析构函数才会释放ps和use指向的空间。
// 但是hp_ptr指向的空间不会被销毁。

c++ 拷贝构造函数、拷贝运算符、析构函数的更多相关文章
- [c++基础]3/5原则--拷贝构造函数+拷贝赋值操作符
/* * main.cpp * * Created on: Apr 7, 2016 * Author: lizhen */ #include <iostream> #include &qu ...
- 拷贝构造函数 & 拷贝赋值运算符
一.拷贝构造函数 1. 形式 class A { public: // ... A(const A &); // 拷贝构造函数 }; 2. 合成拷贝构造函数 编译器总会为我们合成一个拷贝构造函 ...
- C++ 类 & 对象-类成员函数-类访问修饰符-C++ 友元函数-构造函数 & 析构函数-C++ 拷贝构造函数
C++ 类成员函数 成员函数可以定义在类定义内部,或者单独使用范围解析运算符 :: 来定义. 需要强调一点,在 :: 运算符之前必须使用类名.调用成员函数是在对象上使用点运算符(.),这样它就能操作与 ...
- 类string的构造函数、拷贝构造函数和析构函数
原文:http://www.cnblogs.com/Laokong-ServiceStation/archive/2011/04/19/2020402.html 类string的构造函数.拷贝构造 ...
- 编写类String的构造函数、拷贝构造函数、析构函数和赋值函数
一.题目: class String { public: String(const char *str = NULL); // 普通构造函数 String(const String &othe ...
- C++基础 (3) 第三天 构造函数 构造函数初始化列表 拷贝构造函数 析构函数 静态成员变量
// 同类之间无私处 2构造函数 3析构函数 4构造函数的种类和析构函数的顺序 结论:析构函数的调用顺序,跟对象的构造顺序相反,谁先构造,谁最后一个被析构. 拷贝构造函数: 注意: 等号写在下面和写在 ...
- C++的转换构造函数、拷贝构造函数、赋值运算符重载
1 转换构造函数 C++的转换构造函数是只有一个参数的构造函数.当程序试图将一个其他类型的对象或基本类型值赋给该类的一个待初始化对象时(如Person p="Dean";) ...
- C++构造函数 & 拷贝构造函数 & 派生类的构造函数 & 虚继承的构造函数
构造函数 ,是一种特殊的方法 .主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中 .特别的一个类可以有多个构造函数 ,可根据其参数个数的不同或参数 ...
- 对C++拷贝构造函数的一点理解
一. 什么是拷贝构造函数 先看一个简单的例子: #include <iostream> using namespace std; class CExample { private: int ...
- 如何避免被C++默认拷贝构造函数忽悠?
一.背景介绍 因为工作关系,需要用到C++编程.对于我来说,虽然一直从事的是linux平台下的嵌入式软件开发,但深入用到C++的特性的地方并不多.对于C++,用得最多的无非是指针. ...
随机推荐
- SQL高级优化(二)之MySQL架构
一.架构 想要学好SQL优化就必须从对应数据库的基本架构开始学习 架构图如下 二.架构分析 1. 连接管理与安全验证 MySQL有连接池(Connection Pool)管理客户端的连接. ...
- 正则验证&模态框
在日常生活中,凡是需要表单验证的都会用到正则验证.下面拿一个简单的带有模态框的正则验证的小demo看一下 <style> /* 遮罩层 */ .ma ...
- js实现工具函数中groupBy数据分组
数据 this.tableData = [ {id: 1, name: '测试', number: 1, price: 0}, {id: 2, name: '测试', number: 1, price ...
- C 库函数 - pow()
1.C 标准库 - <math.h> 2.C 库函数 double pow(double x, double y) 返回 x 的 y 次幂,即 xy. 3.pow() 函数的声明. dou ...
- JUC之Fork/Join框架
Fork/Join框架和异步 定义: Fork/Join框架是Java 7提供的一个用于并行执行任务的框架,是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架.类似于递归或 ...
- golang中的标准库http
Go语言内置的net/http包十分的优秀,提供了HTTP客户端和服务端的实现. http客户端 基本的HTTP/HTTPS请求 Get.Head.Post和PostForm函数发出HTTP/HTTP ...
- 集合框架-Map重点方法entrySet演示
1 package cn.itcast.p6.map.demo; 2 3 import java.util.HashMap; 4 import java.util.Iterator; 5 import ...
- 『无为则无心』Python函数 — 40、Python自定义异常
目录 1.使用 raise 语句来抛出异常 (1)抛出异常类 (2)抛出异常类的实例 2.自定义异常类 (1)简单实现 (2)完整实现 在Python中,抛出自定义异常的语法为 raise 异常类对象 ...
- 如何美化 Matplotlib 3D坐标系
前言 ~mpl_toolkits.mplot3d 生成的3D坐标系背景色是灰色的,刻度线也向内延伸了,如果搭配上其他白色背景的 2D 图,看起来很奇怪,比如下面这张图: 网上有一些办法可以将3D坐标区 ...
- 寻找写代码感觉(十六)之 集成Validation做参数校验
写在前面 今天是大年初五了... 不知不觉,又要上班了,美好的假期只剩一天了,有点不舍呢! 也不知道为什么,总感觉像在做梦一样,像没睡醒一样,并不是因为眼睛小,更多应该是自寻烦恼,想得多罢了. 参数校 ...