广告位联系
返回顶部
分享到

解读构造函数的调用规则、深拷贝与浅拷贝

C语言 来源:互联网 作者:佚名 发布时间:2024-11-14 21:18:43 人浏览
摘要

1.调用规则 默认情况下,C++至少会给一个类添加三个函数: 默认构造函数(无参,函数体为空) 默认析构函数(无参,函数体为空) 默认拷贝构造函数,对属性进行值拷贝 调用规则: 1.如果

1.调用规则

默认情况下,C++至少会给一个类添加三个函数:

  • 默认构造函数(无参,函数体为空)
  • 默认析构函数(无参,函数体为空)
  • 默认拷贝构造函数,对属性进行值拷贝

调用规则:

1.如果用户定义了有参构造函数,C++将不在提供默认无参构造函数,但是会提供默认拷贝构造函数。

如上图,我们给类A提供了一个有参的构造函数,所以此时,如果再去主函数定义一个无参的对象时,编译器就会提示“类A不存在默认构造函数”,这就说明如果自己定义了有参构造函数,那么就不会提供默认的无参构造函数。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

#include<iostream>

using namespace std;

class A {

public:

    int num;

    A(int num) {

        this->num = num;

    }

};

int main()

{

    A a(5);

    A b(a);

    cout << b.num;

    return 0;

}

在类中我们只提供了一个有参的构造函数,我们在主函数中定义一个b对象,传的是对象a,那么它便会走拷贝构造的函数,如果能够输出b.num的值为5的话,则说明提供了默认的拷贝构造函数。

通过打印b的num,发现确实是5.那么就会提供默认的构造函数。

2.如果用户定义拷贝构造函数,c++不会提供其他构造函数

可以看到当我们仅在类A中写了一个拷贝构造函数时,再去主函数中定义一个无参的对象a时,就会报错,提示“类A不存在默认构造函数”。

2.深拷贝和浅拷贝问题

浅拷贝:就是简单的赋值操作

存在的问题:如果有指针指向堆区内存时,不同对象的指针成员指向的是同一块堆区内存。在对象进行释放时,该堆区会被释放两次。当一个对象修改堆区的内容时,另一个对象的内容也会随着改变。

深拷贝:申请同样大小的堆区内存,保证两个堆区的内容一样。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

#include<iostream>

using namespace std;

class A {

    int num;

    int* p;

public:

    A() {

        num = 0;

        p = nullptr;

        cout << "调用无参构造" << endl;

    }

    A(int a) {

        num = a;

        p = new int[num];

        cout << "调用有参构造" << endl;

    }

    ~A() {

        if (p)delete[]p;

    }

};

 

int main() {

    A a(3);

    A b = a;

    return 0;

}

在类A中我们定义了一个指针变量,在有参构造函数中,我们在堆区开辟了一块空间。在主函数数中,定义对象b要走拷贝构造函数。下面我们来运行这段代码:

发现报错了,原因就是对象a和对象b的成员变量*p指向的是同一块堆区内存,再调用析构函数时,对象b先把这块堆区内存释放了,当对象a调用析构函数时,此时那块堆区内存已经不存在了,所以会出现访问内存失败,导致程序崩溃。

那么解决的办法就是重写拷贝构造函数,让他们指向不同的堆区区域。代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

#include<iostream>

using namespace std;

class A {

    int num;

    int* p;

public:

    A() {

        num = 0;

        p = nullptr;

        cout << "调用无参构造" << endl;

    }

    A(int a) {

        num = a;

        p = new int[num];

        cout << "调用有参构造" << endl;

    }

    A(const A& other) {//万能引用,避免实参修改形参

        num = other.num;

        p = new int[num];//保证内存大小相同

        for (int i = 0; i < num; i++) {

            p[i] = other.p[i];//保证数据相同

        }

        cout << "调用拷贝构造" << endl;

    }

    ~A() {

        if (p)delete[]p;

        cout << "调用析构函数" << endl;

    }

};

 

int main() {

    A a(3);

    A b = a;

    return 0;

}

通过再在堆区上开辟一块内存,让这块堆区内存上的内容和对象a的堆区内容一样就行,这就是深拷贝。

程序能正常运行。

3.string类的拷贝构造练习

可以通过下面这个自定义string类进一步加深对深拷贝的理解。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

#include<iostream>

using namespace std;

class String {

    int size;

    char* p;

public:

    String() {

        p = nullptr;

        size = 0;

    }

    String(const char* p) {

        size = strlen(p);

        this->p = new char[size + 1];//\0,所以加一

        strcpy_s(this->p, size + 1, p);

    }

    ~String() {

        if (p)  delete[]p;

    }

    String(const String& other) {

        this->size = other.size;

        this->p = new char[size + 1];

        strcpy_s(this->p, size + 1,other.p);

    }

    void print() {

        cout << p<<endl;

    }

};

int main() {

    String str = "abcde";

    String str2(str);

    str2.print();

    return 0;

}


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。

您可能感兴趣的文章 :

原文链接 :
相关文章
  • Java打印星号图案和数字图案的代码
    使用循环和控制语句打印图案 在 Java 中,使用循环和控制语句是打印图案的最佳方法。循环可以帮助你重复执行一段代码,直到满足某个条
  • 解读构造函数的调用规则、深拷贝与浅拷贝

    解读构造函数的调用规则、深拷贝与浅拷贝
    1.调用规则 默认情况下,C++至少会给一个类添加三个函数: 默认构造函数(无参,函数体为空) 默认析构函数(无参,函数体为空) 默认
  • Qt音视频功能实现方法

    Qt音视频功能实现方法
    Qt 音视频 在 Qt 中,音频主要是通过QSound类来实现。但是需要注意的是QSound类只支持播放wav格式的音频文件。也就是说如果想要添加音频效果
  • C++的dynamic代码介绍
    在C++编程中,dynamic_cast是处理多态类型转换的关键工具,允许在复杂继承结构中安全地将基类指针或引用转换为派生类指针或引用。通过利
  • C++中使用不同平台的时间函数及对比介绍
    在 C++ 编程中,时间函数的选择对于性能测量、任务调度和时间戳记录至关重要。不同的操作系统提供了不同的时间函数,同时在同一个平台
  • C++中VTK9.3.0刻度标签重叠的问题记录

    C++中VTK9.3.0刻度标签重叠的问题记录
    本文采用VTK9.3.0版本,其他版本如VKT8.0亦有同样的问题 VTK显示文本时,Z轴刻度标签出现了重叠,如下图: 寻找好久,没有找到设置标签间距
  • C++拷贝构造函数和赋值运算符重载介绍

    C++拷贝构造函数和赋值运算符重载介绍
    一,拷贝构造函数 1. 什么是拷贝构造函数 拷贝构造函数是特殊的构造函数。是用一个已经存在的对象,赋值拷贝给另一个新创建的已经存在
  • C++中生成随机数的方法介绍

    C++中生成随机数的方法介绍
    背景 C++ 11 在头文件 #include 中定义了随机数库,也可以使用 C 中生成随机数的方法。 C 生成随机数 概述 C 语言中使用 rand() 函数产生 0 ~ RA
  • c++项目中后缀名vcxproj和sln的区别及说明
    c++项目后缀名vcxproj和sln区别 `.vcxproj 文件 是 Visual Studio 中用于存储 C++ 项目配置和设置的 XML 文件。 它包含了项目的编译选项、链接选项、
  • C++项目实战之makefile使用

    C++项目实战之makefile使用
    makefile简介 一个工程中的源文件不计其数(一个项目有有很多的文件),现在的项目基本都是按模块进行划分的,而这些模块存放在若干目录中
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计