C++的拷贝构造函数、operator=运算符重载,深拷贝和浅拷贝、explicit关键字
原文地址:https://blog.csdn.net/shine_journey/article/details/53081523
1、在C++编码过程中,类的创建十分频繁。
简单的功能,当然不用考虑太多,但是从进一步深刻理解C++的内涵,类的结构和用法,编写更好的代码的角度去考虑,我们就需要用到标题所提到的这些内容。
2、先上代码
- // testSingleMode.cpp : 定义控制台应用程序的入口点。
- //
- #include "stdafx.h"
- #include <iostream>
- using namespace std;
- class Complex
- {
- private:
- double m_real;
- double m_imag;
- public:
- Complex(void){
- m_real = 0.0;
- m_imag = 0.0;
- }
- Complex(double real, double imag){
- m_real = real;
- m_imag = imag;
- }
- Complex(const Complex & c){ //这里就是最经典的拷贝构造函数了
- m_real = c.m_real;
- m_imag = c.m_imag;
- }
- Complex &operator = (const Complex &rhs){ //这里就是最经典的operator=操作符重载了
- if (this == &rhs){
- return *this;
- }
- this->m_real = rhs.m_real;
- this->m_imag = rhs.m_imag;
- return *this;
- }
- explicit Complex::Complex(double r){ //explicit的用法,只适用于1个参数的情况
- m_real = r;
- m_imag = 0.0;
- }
- };
- int main()
- {
- Complex c1, c2; //调用 第15行 默认无参数的构造函数
- Complex c3(1.0, 2.5); //调用 第20行 具有2个形参的构造函数
- //Complex c3 = Complex(1.0, 2.5); //和上一行是一个意思,所以这个注释了
- c1 = c3; //调用 第30行 重载operator=运算符
- c2 = c3; //调用 第30行 重载operator=运算符
- //c2 = 5.2; //隐式转换,需要去掉41行的explicit关键字,才可编译通过
- Complex c5(c2); //调用 第25行 拷贝构造函数
- Complex c4 = c2; //调用 第25行 拷贝构造函数
- getchar();
- return 0;
- }
【注1】explicit 只适用于构造函数只含有1个参数的情况,加上这个关键字,意味着不支持构造函数隐式转换,可以避免一些误解。如果去掉这个关键字,那么代码里面的:c2 = 5.2 ; 就是可以执行的了。
【注2】为什么函数中可以直接访问对象c的私有成员?
答:(网上)因为拷贝构造函数是放在本身这个类里的,而类中的函数可以访问这个类的对象的所有成员,当然包括私有成员了。
3、上面代码的注释,已经是非常的清楚了
自定义拷贝构造函数是一种良好的编程风格,它可以阻止编译器形成默认的拷贝构造函数,防止出错。
浅拷贝:如果自己不写拷贝构造函数,系统会默认生成一个,而系统的拷贝构造函数是浅拷贝。
深拷贝:自己写一个拷贝构造函数,系统就不会产生了默认的构造函数了(来自网上说法)。自己写的这个拷贝构造函数,当然会有开辟空间的动作,所以是深拷贝。也就是说,如果生成类的实例的时候,调用了自己写的拷贝构造函数,那么在内存空间上,必然是会开辟新的空间,而不用担心只是一个指针。
在某些状况下,类内成员变量需要动态开辟堆内存,如果实行浅拷贝,也就是把对象里的值完全复制给另一个对象,如A=B。这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。这就出现了问题:当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。
4、总结
(1)深拷贝:如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝。反之,没有重新分配资源,就是浅拷贝。
(2)什么时候用到拷贝构造函数
b.一个对象以值传递的方式从函数返回;
(4)代码例子
- #include "stdafx.h"
- #include <iostream>
- #include <string.h>
- #include <stdio.h>
- #include <stdlib.h>
- using namespace std;
- class Person
- {
- public:
- // 构造函数
- Person(char * pN)
- {
- cout << "一般构造函数被调用 !\n";
- m_pName = new char[strlen(pN) + 1];
- //在堆中开辟一个内存块存放pN所指的字符串
- if (m_pName != NULL)
- {
- //如果m_pName不是空指针,则把形参指针pN所指的字符串复制给它
- strcpy_s(m_pName, strlen(pN) + 1, pN);
- }
- }
- // 下面自己设计复制构造函数,实现“深拷贝”,即不让指针指向同一地址,而是重新申请一块内存给新的对象的指针数据成员
- Person(Person & chs)
- {
- cout << "拷贝构造函数被调用 !\n";
- // 用运算符new为新对象的指针数据成员分配空间
- m_pName = new char[strlen(chs.m_pName) + 1];
- if (m_pName)
- {
- // 复制内容
- strcpy_s(m_pName, strlen(chs.m_pName) + 1, chs.m_pName);
- }
- // 则新创建的对象的m_pName与原对象chs的m_pName不再指向同一地址了
- }
- //// 系统创建的默认复制构造函数,只做位模式拷贝
- //Person(Person & p)
- //{
- // //使两个字符串指针指向同一地址位置
- // m_pName = p.m_pName;
- //}
- ~Person()
- {
- delete m_pName;
- }
- void getName(){
- cout << m_pName << endl;
- }
- private:
- char * m_pName;
- };
- void main()
- {
- Person man("lujun");
- man.getName();
- Person woman(man);
- woman.getName();
- getchar();
- }
程序运行环境: VS2013
输出结果:
C++的拷贝构造函数、operator=运算符重载,深拷贝和浅拷贝、explicit关键字的更多相关文章
- C++的转换构造函数、拷贝构造函数、赋值运算符重载
1 转换构造函数 C++的转换构造函数是只有一个参数的构造函数.当程序试图将一个其他类型的对象或基本类型值赋给该类的一个待初始化对象时(如Person p="Dean";) ...
- C++ 一个例子彻底搞清楚拷贝构造函数和赋值运算符重载的区别
class TestChild { public: TestChild() { x=; y=; printf("TestChild: Constructor be called!\n&quo ...
- C++有关拷贝构造函数(默认/浅/深拷贝构造函数)
拷贝结构函数顾名思义就是复制对象. 先讲一下默认拷贝函数: 默认拷贝就是直接赋值,让程序调用默认拷贝结构函数. Student p1; Student p2 = p1//或者Student p2(p1 ...
- C++“拷贝构造函数”和“等号重载”有什么区别?
CTypeA(const CTypeB& b)CTypeA& operator=(const CTypeB& b)一直没弄懂这两个有什么区别.只知道,重载了=号,下面复制的时候 ...
- c++ 拷贝构造函数(重点在内含指针的浅拷贝和深拷贝)
今天同事问了一个关于拷贝构造函数的问题,类中包含指针的情况,今天就来说说c++的拷贝构造函数. c++的拷贝构造函数是构造函数的一种,是对类对象的初始化,拷贝构造函数只有一个参数就是本类的引用. 注意 ...
- Swift语言精要 - Operator(运算符重载)
运算符重载 Swift的这一语言特性或许应该启发于C++ class Vector2D { var x : Float = 0.0 var y : Float = 0.0 init (x : Floa ...
- C++基础-4-封装(构造函数与析构函数,深拷贝与浅拷贝,静态成员,this,友元,const修饰成员函数)
4. 封装 4.1.1 封装的意义 1 #include<iostream> 2 #include<string> 3 using namespace std; 4 5 con ...
- 【转】 c++拷贝构造函数(深拷贝,浅拷贝)详解
c++拷贝构造函数(深拷贝,浅拷贝)详解 2013-11-05 20:30:29 分类: C/C++ 原文地址:http://blog.chinaunix.net/uid-28977986-id-3 ...
- c++拷贝构造函数(深拷贝,浅拷贝)详解
一.什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: ; int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量. 下面 ...
随机推荐
- JSP实现界面的自动跳转的几种方式
下面来谈一谈在jsp中实现的几种界面自动跳转的方法. 使用JavaScript脚本 <html> <script language=javascript> function o ...
- ADO.NET常用方法释义
先列个列表,下面的就是常用的数据库操作的方法. ExecuteNonQuery 释义:对链接执行的SQL语句,并返回受影响的行数(注意:用它来执行目录操作,如查询数据库的结构,创建表等数据库对象,或通 ...
- OkHttp框架从入门到放弃,解析图片使用Picasso裁剪,二次封装OkHttpUtils,Post提交表单数据
OkHttp框架从入门到放弃,解析图片使用Picasso裁剪,二次封装OkHttpUtils,Post提交表单数据 我们这片博文就来聊聊这个反响很不错的OkHttp了,标题是我恶搞的,本篇将着重详细的 ...
- (二)php的常量和变量
[php在命令行下接收参数] 如果在命令行调试php,传入的参数通过$argv获取,注意其中包含了文件名这一个元素,数组中元素的个数通过$argc获取. [可变变量] 指的是变量的名称可变,变量的标识 ...
- jquery easyui datagrid 分页实现---善良公社项目
接着上篇文章,接下来给大家分享分页的实现,分页其实多多少少见过很有几种,框架中带的图片都特别的好看,会给用户以好的使用效果,具体实现,需要自己来补充代码: 图示1: 通常情况下页面数据的分页显示分成真 ...
- Linux的mount命令简介
在Linux系统中,如果要使用硬盘.光盘.软盘或MO盘等存储设备,必须先进行挂装(Mount).当存储设备挂装完成之后,就可以将其作为一个目录来进行访问了.挂装设备需要使用mount命令.执行这一命令 ...
- 单点登录之CAS SSO从入门到精通(第三天)
开场白 各位新年好,上海的新年好冷,冷到我手发抖. 做好准备全身心投入到新的学习和工作中去了吗?因为今天开始的教程很"变态"啊,我们要完成下面几件事: 自定义CAS SSO登录界面 ...
- 【Unity Shaders】Diffuse Shading——向Surface Shader添加properties
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
- 从"按层次输出二叉树"到"求解二叉树深度"的总结
本文是在学习中的总结,欢迎转载但请注明出处:http://write.blog.csdn.net/postedit/41964669 最近在刷LeetCode上的算法题,发现好多题目的解题思路大体是一 ...
- Android OnLowMemory和OnTrimMemory
1.OnLowMemory 是Android提供的API,在系统内存不足,所有后台程序(优先级为background的进程,不是指后台运行的进程)都被杀死时,系统会调用OnLowMemory. 系统提 ...