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

 更新时间:2024年11月13日 14:08:58   作者:gemluoye  
本文主要介绍了C++中的默认构造函数、拷贝构造函数以及深拷贝和浅拷贝的概念,并通过实际代码示例进行了详细讲解

1.调用规则

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

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

调用规则:

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

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

#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.深拷贝和浅拷贝问题

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

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

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

#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调用析构函数时,此时那块堆区内存已经不存在了,所以会出现访问内存失败,导致程序崩溃。

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

#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类进一步加深对深拷贝的理解。

#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;
}

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 详解用C语言实现三子棋游戏流程

    详解用C语言实现三子棋游戏流程

    三子棋是一种民间传统游戏,又叫九宫棋、圈圈叉叉、一条龙、井字棋等。将正方形对角线连起来,相对两边依次摆上三个双方棋子,只要将自己的三个棋子走成一条线,对方就算输了
    2021-11-11
  • C++实现四则混合运算计算器

    C++实现四则混合运算计算器

    这篇文章主要为大家详细介绍了C++实现四则混合运算计算器,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-11-11
  • C++可变参数的实现方法

    C++可变参数的实现方法

    可变参数给编程带来了很大的方便,在享受它带来的方便的同时,很有必要了解一下其实现方式,在了解编程语言的同时,也可以扩展编程的思路。
    2013-03-03
  • 浅谈C++模板元编程

    浅谈C++模板元编程

    本篇文章主要介绍了浅谈C++模板元编程,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-12-12
  • C语言实现弹跳小球

    C语言实现弹跳小球

    这篇文章主要为大家详细介绍了C语言实现弹跳小球,设置了小球分数及过关难度,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-03-03
  • win10环境下C++ vs2015编译opencv249的教程

    win10环境下C++ vs2015编译opencv249的教程

    这篇文章主要介绍了win10环境下C++ vs2015编译opencv249的教程,本文分步骤给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-03-03
  • linux下基于C语言的信号编程实例

    linux下基于C语言的信号编程实例

    这篇文章主要介绍了linux下基于C语言的信号编程,实例分析了信号量的基本使用技巧与相关概念,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-07-07
  • C++ 类的静态成员深入解析

    C++ 类的静态成员深入解析

    在C++中类的静态成员变量和静态成员函数是个容易出错的地方,本文先通过几个例子来总结静态成员变量和成员函数使用规则,再给出一个实例来加深印象
    2013-09-09
  • C++ setw()函数的具体使用

    C++ setw()函数的具体使用

    本文主要介绍了C++ setw()函数的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • 详解C++编程中向函数传递引用参数的用法

    详解C++编程中向函数传递引用参数的用法

    这篇文章主要介绍了详解C++编程中向函数传递引用参数的用法,包括使函数返回引用类型以及对指针的引用,需要的朋友可以参考下
    2016-01-01

最新评论