<C++>深浅拷贝与初始化列表技巧你真的会了吗

简介: <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) 语句给身高属性重新开辟空间,这样在调用析构的时候各自清理各自的属性,就解决了这个浅拷贝带来的重复清理问题。


内存图解释


image.png


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


image.png


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


初始化列表


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


语法


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


具体实现


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;直接来看结果:


image.png


相关文章
|
2月前
|
存储 编译器 C++
【C++】深入探索类和对象:初始化列表及其static成员与友元(一)
【C++】深入探索类和对象:初始化列表及其static成员与友元
|
3月前
|
编译器 C++
C++ 类构造函数初始化列表
构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式。
81 30
|
2月前
|
存储 编译器 数据安全/隐私保护
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解2
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解
44 3
|
2月前
|
编译器 C++
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解1
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解
55 3
|
2月前
|
C++
【C++】深入探索类和对象:初始化列表及其static成员与友元(二)
【C++】深入探索类和对象:初始化列表及其static成员与友元
|
2月前
|
编译器 C++
【C++】深入探索类和对象:初始化列表及其static成员与友元(三)
【C++】深入探索类和对象:初始化列表及其static成员与友元
|
2月前
|
C++
C++构造函数初始化类对象
C++构造函数初始化类对象
26 0
|
4月前
|
Dart API 开发工具
Dart ffi 使用问题之Dart API要在C++中使用,该如何初始化
Dart ffi 使用问题之Dart API要在C++中使用,该如何初始化
|
5月前
|
编译器 C++
【C++】详解初始化列表,隐式类型转化,类静态成员,友元
【C++】详解初始化列表,隐式类型转化,类静态成员,友元
|
6月前
|
存储 编译器 C++
【C++】类和对象④(再谈构造函数:初始化列表,隐式类型转换,缺省值
C++中的隐式类型转换在变量赋值和函数调用中常见,如`double`转`int`。取引用时,须用`const`以防修改临时变量,如`const int& b = a;`。类可以有隐式单参构造,使`A aa2 = 1;`合法,但`explicit`关键字可阻止这种转换。C++11起,成员变量可设默认值,如`int _b1 = 1;`。博客探讨构造函数、初始化列表及编译器优化,关注更多C++特性。