C++析构函数与构造函数深拷贝浅拷贝(C++初学面向对象编程)

2023-05-16

文章目录

    • 一、析构函数
    • 二、C++默认生成的函数
    • 三、构造与析构的调用顺序
    • 四、构造函数的浅拷贝
    • 五、构造函数的深拷贝

一、析构函数

1、析构函数的作用
对象消亡时,自动被调用,用来释放对象占用的内存空间。

2、属性特点
(1)名字与类名相同
(2)在前面需要加上"~"
(3)无参数,无返回值(也不能加void)
(4)一个类最多只有一个析构函数
(5)不自定义析构函数C++会生成默认析构函数

二、C++默认生成的函数

在默认情况下,定义一个C++类都会默认生成以下三个函数:

  • 默认构造函数(无参,函数体为空)
  • 默认析构函数(无参,函数体为空)
  • 默认拷贝构造函数(对类中非静态成员进行简单值拷贝)

注意:
若自定义了拷贝构造函数,将不再提供任何构造函数。
若自定义了普通构造函数,将不会提供默认构造函数,但还是会提供默认拷贝构造函数。

三、构造与析构的调用顺序

构造函数是先定义的先调用,而析构函数是先定义的后调用,类似于“栈”存储结构。

class Test
{
    int id;
public:
    Test(int i)
    {
        id = i;
    }
    ~Test()
    {
        cout<<"ID: "<<id<<" 已析构对象内存空间"<<endl;
    };
};
 
Test t0(0);                        //最先创建的对象,最后释放
 
void Func()
{
    static Test t1(1);               //创建静态对象,会在整个程序结束时自动释放
    Test t2(2);             //在Func结束时自动释放
    cout<<"-----Func-----"<<endl;
}
 
int main()
{
    Test t3(3);
    t3 = 10;                         //类型转换构造函数,这里会创建临时对象,将int型转成Test类型对象,在赋值结束后,临时变量销毁
    cout<<"------主函数开始-------"<<endl;
    {
        Test t4(4);                  //花括号代表作用域,不需要等到main方法结束就释放了
    }
    Func();                          //进入Func函数
    cout<<"------主函数结束-------"<<endl;
    return 0;
}

四、构造函数的浅拷贝

就是构造函数只进行简单的值拷贝。

/*浅拷贝*/
#include <iostream>
#include<string.h>
#include<stdlib.h>
using namespace std;

//定义一个类Person 
class Person
{
private:
    char *m_name;  //私有成员数据中定义个指针 
    int m_num;
public:  //共有成员接口 
    Person()  //普通无参构造函数 
    {
        m_name = NULL;  //在构造函数中将指针指向空 
        m_num = 0;
        cout << "已调用无参构造..." << endl;
    }
    Person(char *name,int num)  //普通有参构造函数 
    {
        //为m_name重新申请空间
        m_name = (char *)calloc(1,strlen(name)+1);  //新空间大小刚好为name的长度 
        if(m_name == NULL)  //若私有成员指针仍指向空地址,则输出构造失败 
        {
            cout<<"构造失败"<<endl;
        }
        cout<<"-->已经申请好空间"<<endl;  //否则提示空间申请成功 
        strcpy(m_name,name);  //将传入有参构造的参数指针赋值给成员指针 
        m_num = num;  
        cout<<"已调用有参构造..."<<endl;
    }
    ~Person()  //定义析构函数 
    {
        if(m_name != NULL)  //若成员指针指向空,表示空间已被释放 
        {
            cout<<"m_name的空间已被释放"<<endl;
            free(m_name);  //否则手动释放内存空间 
            m_name = NULL;
        }
        cout<<"析构函数调用结束..."<<endl;
    }

    void showPerson()
    {
        cout << "m_name = " << m_name << ", m_num = " << m_num << endl;
    }
};

//定义有参构造的接口测试函数 
void demo1()
{
    Person p1("Chung", 42607);  //实例化p1对象,调用有参构造函数 
    p1.showPerson();  //调用成员函数输出p1的信息 
    // 浅拷贝
    Person p2= p1; //调用系统的默认拷贝构造(单纯的值拷贝)
}

//定义无参构造的接口测试函数 
void demo2()
{
	Person p3;  //实例化p3对象,调用无参构造函数
	p3.showPerson();  //输出p3的信息
	//浅拷贝
	Person p4= p3;  //简单的值拷贝 
}

//主函数定义 
int main(int argc, char *argv[])
{
    //demo1();  //测试开始 ,有参构造 
    demo2();  //无参构造 
    return 0;
}

(1)测试demo1
01
(2)测试demo2
02
只调用到一半就出错结束了。

五、构造函数的深拷贝

就是通过自定义,拷贝构造函数,完成深拷贝动作,能够将数值和地址都拷贝进去。

#include <iostream>
#include<string.h>
#include<stdlib.h>
using namespace std;

//定义一个类Person 
class Person
{
private:
    char *m_name;  //私有成员数据中定义个指针
    int m_num;
public:
    Person()  //普通无参构造函数 
    {
        m_name = NULL;  //在构造函数中将指针指向空 
        m_num = 0;
        cout << "已调用无参构造..." << endl;
    }
    
    Person(char *name,int num)  //普通有参构造函数 
    {
        //为m_name重新申请空间
        m_name = (char *)calloc(1,strlen(name)+1);  //新空间大小刚好为name的长度 
        if(m_name == NULL)  //若私有成员指针仍指向空地址,则输出构造失败 
        {
            cout<<"构造失败"<<endl;
        }
        cout<<"-->已经申请好空间"<<endl;  //否则提示空间申请成功 
        strcpy(m_name,name);  //将传入有参构造的参数指针赋值给成员指针 
        m_num = num;  
        cout<<"已调用有参构造..."<<endl;
    }
    
    //自定义拷贝构造函数 
    Person(const Person &p)//p是一个引用类型,括号内相当于Box p=b1
    {
        cout << "--------------------拷贝构造函数----------------------" << endl;
        m_name= (char *)calloc(1, strlen(p.m_name)+1);  //在拷贝构造函数中重新申请空间,就能够实现地址的拷贝 
        cout << "空间已被申请" << endl;
        strcpy(m_name, p.m_name);  //将引用对象常量下的m_name拷贝到私有成员数据m_name里 

        m_num= p.m_num;
        cout << "--------------------拷贝构造函数----------------------" << endl;
    }

    ~Person()  //定义析构函数 
    {
        if(m_name != NULL)  //若成员指针指向空,表示空间已被释放 
        {
            cout<<"m_name的空间已被释放"<<endl;
            free(m_name);  //否则手动释放内存空间 
            m_name = NULL;
        }
        cout<<"析构函数调用结束..."<<endl;
    }

    void showPerson()
    {
        cout << "m_name = " << m_name << ", m_num = " << m_num << endl;
    }
};

//定义有参构造的测试函数 
void demo1()
{
    Person p1("Chung", 42607);
    p1.showPerson();

    //通过自定义 拷贝构造函数 完成深拷贝动作
    Person p2= p1;
}

//定义无参构造的测试函数 
void demo2()
{
    Person p3;
    //p3.showPerson();

    //通过自定义 拷贝构造函数 完成深拷贝动作
    Person p4= p3;
    p4.showPerson();
}

//定义主函数 
int main(int argc, char *argv[])
{
    demo1();  //调用测试函数 
    //demo2();
    return 0;
}

(1)测试demo1
03

(2)测试demo2
04

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++析构函数与构造函数深拷贝浅拷贝(C++初学面向对象编程) 的相关文章

随机推荐