C++ Primer笔记9_构造函数_拷贝构造(深拷贝与浅拷贝)
1.构造函数:
>构造函数是一个特殊的、与类同名的成员函数,用于给每一个成员设置适当的初始值。
>构造函数不能有返回值,函数名与类名同样。
>缺省构造函数时,系统将自己主动调用该缺省构造函数初始化对象,缺省构造函数会将全部数据成员都初始化为零或 空。缺省构造函数是不带參数的构造函数。
>创建一个对象时,系统自己主动调用构造函数。
构造函数的特点:
1.构造函数能够重载,传入什么实參决定调用不同版本号的构造函数。
2.构造函数不能声明为const 、也不能声明为virtual;(析构函数能够)
3.一个类假设自己定义了一个构造函数,编译器就不会生成默认构造函数。
4.仅仅有构造函数才有类似初始化列表的形式来初始化成员变量(特别是const成员变量仅仅能在初始化列表中初始化)
样例:
#include <iostream>
#include <new> class Person
{
public:
Person();//默认的构造函数
Person(int n, const string &str);//构造函数的重载
private:
int age;
string *name;
};
2.拷贝构造
先介绍一下深拷贝与浅拷贝:
>浅拷贝: 指的是在对象复制时,仅仅对对象中的数据成员进行简单的赋值;默认拷贝构造函数运行的也是浅拷贝。
大多情况下“浅拷贝”已经能非常好地工作了,可是一旦对象存在了动态成员,那么浅拷贝就会出问题了。
>深拷贝:当类的成员变量有指针类型时,拷贝对象时应该为指针变量又一次分配好空间,避免浅拷贝中仅仅拷贝指针的
值,使得两个指针指向同一块内存空间。
浅拷贝缺陷样例:
#include <iostream>
#include <new> using namespace std; class Person
{
public:
Person();
Person(int n, const string &str);//构造函数重载
~Person();
private:
int age;
string *name;
}; Person::Person():age(0), name(NULL)//构造函数初始化列表,定义时不必写!
{
cout << "Default Person" << endl;
} Person::Person(int n, const string &str):age(n), name(new string(str))
{
cout << "Init Person" << endl;
} Person::~Person()
{
if(name)
{
cout << "~Person " << "name: " << *name << " age: " << age << endl;
}
delete name;
} int main()
{
Person p1(10, string("SCOTT"));
Person p2 = p1; return 0;
}
执行结果:
Init Person
~Person name: SCOTT age: 10
Segmentation fault (core dumped)
程序崩溃原因:
p2由p1初始化而得到,因为我们没有自己定义拷贝构造函数,所以调用的是默认的拷贝构造函数,属于浅拷贝,仅仅对name的值进行了拷贝;p1与p2中的name指针指向同一个new空间,最后调用析构函数时,会造成两次delete而出现段错误。
例如以下图所看到的:
解决方法:自己定义拷贝构造函数! 达到深拷贝的效果
深拷贝样例:
#include <iostream>
#include <new> using namespace std; class Person
{
public:
Person();
Person(int n, const string &str);
Person(const Person &n);
~Person();
private:
int age;
string *name;
}; Person::Person():age(0), name(NULL)
{
cout << "Default Person" << endl;
} Person::Person(int n, const string &str):age(n), name(new string(str))
{
cout << "Init Person" << endl;
}
//自己定义拷贝构造函数
Person::Person(const Person &n)
{
if(n.name)
{
name = new string(*n.name);
age = n.age;
}
} Person::~Person()
{
if(name)
{
cout << "~Person " << "name: " << *name << " age: " << age << endl;
}
delete name;
} int main()
{
Person p1(10, string("SCOTT"));
Person p2 = p1; return 0;
}
执行结果:
Init Person
~Person name: SCOTT age: 10
~Person name: SCOTT age: 10
没有出现段错误,由此可见,上述解决方式可行。
C++ Primer笔记9_构造函数_拷贝构造(深拷贝与浅拷贝)的更多相关文章
- 【C++ Primer | 15】构造函数与拷贝控制
合成拷贝控制与继承 #include <iostream> using namespace std; class Base { public: Base() { cout << ...
- C++ 构造函数_拷贝构造函数
拷贝构造函数
- C++基础-4-封装(构造函数与析构函数,深拷贝与浅拷贝,静态成员,this,友元,const修饰成员函数)
4. 封装 4.1.1 封装的意义 1 #include<iostream> 2 #include<string> 3 using namespace std; 4 5 con ...
- 借jQuery对象拷贝学习深拷贝与浅拷贝
jQuery.extend([deep], target, object1, [objectN]) 即用一个或多个其他对象来扩展一个对象,返回被扩展的对象. deep:如果设为true,则递归合并. ...
- 构造函数,拷贝构造和赋值运算符调用时机,explicit,
#include<iostream> #include <stdio.h> using namespace std; class test{ int mvalue; publi ...
- C++构造函数实例——拷贝构造,赋值
#define _CRT_SECURE_NO_WARNINGS //windows系统 #include <iostream> #include <cstdlib> #incl ...
- C++ Primer笔记1_转义字符_标准库类型string_标准库类型vector
1.转义字符 一般有两种方式: \x后紧跟1个或多个十六进制数字.或\后紧跟1.2.3个八进制数字,当中数字部分是字符相应的数值. #include <iostream> using na ...
- [terry笔记]11gR2_DataGuard搭建_拷贝数据文件
11gR2搭建dataguard环境: 自己做的实验,后续按照rman模式搭建.主备切换.模式调整等实验会陆续发上来. primary: OS:oel 6.4 database:11.2.0.4.0 ...
- python的拷贝(深拷贝和浅拷贝)
今天看了几篇关于python拷贝的博文,感觉不太清楚,所以我就自己做实验试一下,特此记录. 拷贝是针对组合对象说的,比如列表,类等,而数字,字符串这样的变量是没有拷贝这一说的. 实现拷贝有: 1.工厂 ...
随机推荐
- mongodb debug
1,MongoDb log use local; db.startup_log.find();
- html5 laboratory - drawing in the canvas
html5 laboratory - drawing in the canvas Creating a bar chart with canvas 21st February 2010 The exp ...
- canvas.js | CLiPS
canvas.js | CLiPS canvas.js The canvas.js module is a simple and robust JavaScript API for the HTML5 ...
- 网易云课堂_C++开发入门到精通_章节6:多态
课时33示例--为多态基类声明虚析构函数 微软校园招聘笔试题 #include <iostream> class Base { public: char Value() { return ...
- Unity 为自己组件添加公共方法
为什么需要跟你的组件添加公共方法呢? 留一条后路嘛,万一你那天想起要给全部的组件添加一个方法. 此时我只能告诉你慢慢修改吧累死你 子组件:A ,父组件:B继承方式: A -> B –> ...
- Primes on Interval(二分 + 素数打表)
Primes on Interval Time Limit:1000MS Memory Limit:262144KB 64bit IO Format:%I64d & %I64u ...
- ComponentName的意思
ComponentName是用来打开其它应用程序中的Activity或服务的. 使用方法: Intent i=new Intent(); i.setComponent(new ComponentNam ...
- Hadoop中SequenceFile的使用
1.对于某些应用而言,须要特殊的数据结构来存储自己的数据. 对于基于MapReduce的数据处理.将每一个二进制数据的大对象融入自己的文件里并不能实现非常高的可扩展性,针对上述情况,Hadoop开发了 ...
- 使用 React 和 Flux 创建一个记事本应用
React,来自 Facebook,是一个用来创建用户界面的非常优秀的类库.唯一的问题是 React 不会关注于你的应用如何处理数据.大多数人把 React 当做 MV* 中的 V.所以,Facebo ...
- linux安装chrome
wget http://chrome.richardlloyd.org.uk/install_chrome.sh chmod u+x install_chrome.sh ./install_chrom ...