C++细讲深浅拷贝与初始化列表如何操作

 更新时间:2022年05月27日 10:00:21   作者:对象new不出来  
C++对象特性里的拷贝构造函数有更深入的含义,而且面试曾经问过关于拷贝的析构问题,那么今天就好好解析一下深浅拷贝的问题;还有初始化列表的形式,这个在给对象属性初始化的时候非常方便,建议大家熟练掌握,话不多说,开始正文

深浅拷贝区别

上一节简单提了编译器会默认给我们提供值拷贝构造函数,结果是新的对象会拥有和传入对象一样的属性,由编译器提供的拷贝构造被称为浅拷贝构造,而由我们自己编写的不同于编译器提供的拷贝构造函数就叫深拷贝构造了,举个典型的例子说明。

代码解释

#include<iostream>
using namespace std;
//深浅拷贝问题,存在经典的坑,面试考过
class Person
{
public:
	Person(int age,int height)
	{
		m_age = age;
		m_Height = new int(height);
		cout << "Person 的有参构造函数调用" << endl;
	}
	//自己写不同于编译器的拷贝构造函数属于深拷贝
	Person(const Person& p)
	{
		cout << "拷贝构造函数调用" << endl;
		m_age = p.m_age;
		//m_Height = p.m_Height;
		/*编译器默认执行上行代码
		新开辟的地址相同,会导致调用析构函数时违法操作,无法访问内存*/
		m_Height =new int(*p.m_Height);
	}
	~Person()
	{
		//析构代码,将堆区开辟的数据做释放操作
		if (m_Height != NULL)
		{
			delete m_Height;
			m_Height = NULL;
		}
		cout << "~Person 的析构构造函数调用"<<endl;
	}
	int m_age;
	int* m_Height;
};
void test()
{
	Person p1(20,180);
	Person p2(p1);
	cout << "p2.age= " << p2.m_age << " p2.height=" << *p2.m_Height << endl;
}
int main()
{
	test();
	system("pause");
}

创建Person类,设置m_age和指针类型*m_Height为私有属性;依次对Person类设置有参构造和拷贝构造函数以及析构函数;前面析构函数一直没有什么作用,其实它是用来清理对象的,析构函数会在程序结束前自动调用,这时候就可以使用delete清理掉;

特别注意

Person(const Person& p)
	{
		cout << "拷贝构造函数调用" << endl;
		m_age = p.m_age;
		//m_Height = p.m_Height;
		/*编译器默认执行上行代码
		新开辟的地址相同,会导致调用析构函数时违法操作,无法访问内存*/
		m_Height =new int(*p.m_Height);
	}
	~Person()
	{
		//析构代码,将堆区开辟的数据做释放操作
		if (m_Height != NULL)
		{
			delete m_Height;
			m_Height = NULL;
		}
		cout << "~Person 的析构构造函数调用"<<endl;
	}

这里不能使用编译器提供的浅拷贝,如果直接使用m_Height=p.m_Height,毫无疑问这两个属性地址相同,那么在调用析构函数的时候,p1先释放内存,这时候虽然有一个NULL判断,但是此块内存已经被删除,再次访问都会提示错误,这是很危险的,所以我们需要用深拷贝解决重复删除的问题。使用m_Height=new int(*p.m_Height) 语句给身高属性重新开辟空间,这样在调用析构的时候各自清理各自的属性,就解决了这个浅拷贝带来的重复清理问题。

内存图解释

上面是浅拷贝的p1、p2对象的内存示意图,两次析构会重复当问0x00011地址,但是当这个地址被删除后,是不允许再次访问的。

利用我们设置的深拷贝构造后,地址不一样,各自删除各自的地址,解决问题

初始化列表

初始化列表用来给属性初始化

语法

普通构造函数+:+ 类属性(变量或常量)+ {}

具体实现

class Person
{
public:
	Person() :m_age(20), m_sex(1), m_height(180){}
	Person(int a, int b, int c) :m_age(a), m_sex(b), m_height(c){}
	int m_age;
	int m_sex;
	int m_height;
};
int main()
{
	Person p1;
	Person p2(10, 20, 30);
	cout << "年龄为:" << p1.m_age;
	cout << "性别为:" << p1.m_sex;
	cout << "身高为:" << p1.m_height<<endl;
	cout << "年龄为:" << p2.m_age;
	cout << "性别为:" << p2.m_sex;
	cout << "身高为:" << p2.m_height << endl;;
}

主函数中p1调用无参构造函数,各属性初始化为属性()括号里面的值;p2调用有参构造函数,将实参10,20,30分别传给a,b,c,然后a的值传给m_age,b的值传给m_sex;c的值传给m_height;直接来看结果:

总结

C++对象特性的深浅拷贝和初始化列表到这里就分享完了,那麽意味着对象的初始化和清理就结束了,到后面会讲一下静态成员和类对象作为类成员的一个案例,用于巩固这部分知识点,希望下篇文章也可以得到你们的青睐

到此这篇关于C++细讲深浅拷贝与初始化列表如何操作的文章就介绍到这了,更多相关C++深浅拷贝内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • c++异常处理机制示例及详细讲解

    c++异常处理机制示例及详细讲解

    本篇文章主要是对c++异常处理机制示例进行了介绍,需要的朋友可以过来参考下,希望对大家有所帮助
    2014-02-02
  • C语言函数指针的使用详解

    C语言函数指针的使用详解

    在C语言中,函数指针是指向函数的指针变量,本文主要介绍了C语言函数指针的使用详解,具有一定的参考价值,感兴趣的可以了解一下
    2024-01-01
  • C++优先队列用法案例详解

    C++优先队列用法案例详解

    这篇文章主要介绍了C++优先队列用法案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • 整型数据在内存中存储方式的讲解

    整型数据在内存中存储方式的讲解

    今天小编就为大家分享一篇关于整型数据在内存中存储方式的讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-02-02
  • C++实现比较日期大小的示例代码

    C++实现比较日期大小的示例代码

    这篇文章主要为大家详细介绍了如何使用C++实现比较日期大小的功能,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的可以了解一下
    2023-04-04
  • C语言实现线性表的基本操作详解

    C语言实现线性表的基本操作详解

    线性表是最基本、最简单、也是最常用的一种数据结构。一个线性表是n个具有相同特性的数据元素的有限序列,这篇文章带你学习如何通过C语言实现线性表的顺序存储和链式存储
    2021-11-11
  • 使用C语言详解霍夫曼树数据结构

    使用C语言详解霍夫曼树数据结构

    这篇文章主要介绍了使用C语言详解霍夫曼树数据结构,包括一道AMC相关的例题演示需要的朋友可以参考下
    2015-08-08
  • C++ 超详细深入分析单例模式

    C++ 超详细深入分析单例模式

    单例模式(Singleton Pattern)是最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式,这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建
    2022-03-03
  • C语言开发实现扫雷游戏

    C语言开发实现扫雷游戏

    这篇文章主要为大家详细介绍了C语言开发实现扫雷游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-11-11
  • C语言堆与二叉树的顺序结构与实现

    C语言堆与二叉树的顺序结构与实现

    堆是计算机科学中一类特殊的数据结构的统称,通常是一个可以被看做一棵完全二叉树的数组对象。而堆排序是利用堆这种数据结构所设计的一种排序算法。本文将详细介绍堆与二叉树的顺序结构与实现,需要的可以参考一下
    2022-05-05

最新评论