C++从入门到精通 (3) (适合C入门后C++进阶)连载!! 连载!!

本文详细介绍了C++中的构造函数(包括无参、有参和拷贝构造),析构函数的作用和使用场景,以及动态对象创建(new和delete)和初始化列表的重要性。特别强调了拷贝构造的应用,尤其是在涉及动态内存和对象成员初始化时。
摘要由CSDN通过智能技术生成

😀人生的成功,不在于拿到一幅好牌,而是怎样将坏牌打好。你缺少的不是金钱,而是能力,经验和机会。所有的抱怨,不过是逃避责任的借口。一起加油!!

目录

🌹构造于析构

🌷构造函数(重要)

🌷构造分类

🌷析构函数(重点)

🌷拷贝构造函数(重要)

🌷拷贝构造应用场景

🌹初始化列表(重要)

🌷基本初始化列表

🌷对象成员初始化列表

🌷explicit关键字(了解)

🌹动态对象创建(new delete)

🌷new和delete

🌷数组的创建

🌷对象的创建

🌷对象数组的创建

🌷new的拷贝构造


构造于析构

构造函数(重要)

构造函数,在创建对象时系统会自动调用的函数;结构于成员函数类似 没有返回值

析构函数的名 = 类名 构造函数可以带参数(有参构造);构造函数必须是公共类型

class Data{
  Data()    //无参构造函数
  {};  
};

构造分类

构造函数分为无参构造有参构造(赋值和拷贝) 有参构造一般用于做初始化工作

class Data
{
private:
     int m_A;
     int m_B;
public:
     //构造函数可以重载
     Data()
     {
         cout<<"无参构造"<<endl;
     }
     Data(int a)
     {
         m_A = a;
         cout<<"一个参数构造函数"<<endl;
     }
     Data(int a,int b)
     {
         m_A = a;
         m_B = b;
         cout<<"两个参数构造函数"<<endl;
     }
};


void test_01()
{
    Data d1;       //隐式调用--推荐       无参构造
    Data db1 = Data();  //显示调用

    Data d2(10);    //一个参数构造函数 --推荐
    Data db2 = Data(10);    //显示调用
    Data d3(10,20); //两个参数构造函数
}

注意:当我们不写构造函数时,系统会自动产生无参构造函数 当自定义了构造函数后 系统将不会自动产生无参构造函数

析构函数(重点)

写法:由~和类名组成;析构函数不能带参数 所以析构函数没有重载; 比无参构造只多了~

调用了析构函数意味着我们要释放资源了

当我们不写构造函数 系统会自动生成

场景:我们在类成员中开辟了堆区空间需要释放 我们才必须要写析构函数

class Data
{
private:
     int m_A;
     int m_B;
public:
     //构造函数可以重载
     Data()
     {
         cout<<m_A<<"无参构造"<<endl;
     }
     Data(int a)
     {
         m_A = a;
         cout<<m_A<<"一个参数构造函数"<<endl;
     }
     Data(int a,int b)
     {
         m_A = a;
         m_B = b;
         cout<<m_A<<"两个参数构造函数"<<endl;
     }
     ~Data()
     {
        cout<<m_A<<"析构函数"<<endl;
     }
};

void test_01()
{
    Data d1;       //隐式调用--推荐       无参构造
    Data db1 = Data();  //显示调用

    Data d2(10);    //一个参数构造函数 --推荐
    Data db2 = Data(11);    //显示调用
    Data d3(12,13); //两个参数构造函数
}

注意:析构函数和构造函数执行顺序相反。

拷贝构造函数(重要)

拷贝构造函数: 有参构造的一种

注意:如果用户不提供拷贝构造 编译器会提供一个默认构造函数(浅拷贝).

应用场景:只有类指针成员变量在堆区中开辟空间时 才有必要实现拷贝构造(深拷贝)

class Data
{
private:
     int m_A;
public:
     //构造函数可以重载
     Data()
     {
         cout<<"无参构造"<<endl;
     }
     Data(int a)
     {
         m_A = a;
         cout<<m_A<<"有参构造函数"<<endl;
     }
     ~Data()
     {
        cout<<"析构函数"<<endl;
     }
};

void test_01()
{
    Data d1(10);
    Data d2 = d1;   //调用了系统拷贝构造函数
}

拷贝构造应用场景

类成员开辟空间 系统默认拷贝构造函数为浅拷贝 不会重新开辟空间 使用析构函数释放时 会出现重复释放(访问系统空间) 所以需要我们自定义拷贝构造函数 实现深拷贝
 

class Person
{
private:
    char *m_Name;
    int m_Age;
public:
    Person()
    {
        cout<<"无参构造"<<endl;
    }
    Person(char *name,int age)
    {
        m_Name = (char*)malloc(strlen(name)+1);
        strcpy(m_Name,name);
        m_Age = age;
        cout<<"有参构造"<<endl;
    }
    Person(const Person &p)    //深拷贝 开辟新的空间
    {
        m_Age = p.m_Age;
        m_Name = (char*)malloc(strlen(p.m_Name)+1);
        strcpy(m_Name,m_Name);
        cout<<"拷贝构造"<<endl;
    }
    ~Person()
    {
        if(m_Name != NULL)
        {
            free(m_Name);
            m_Name = NULL;
        }
        cout<<"析构函数"<<endl;
    }
};

void test_01()
{
    Person p1("zangsan",18);    //有参构造
    Person p2(p1);              //拷贝构造
}

当类属性需要开辟空间时 就需要自定义拷贝函数 并使用析构函数释放空间

初始化列表(重要)

前面学习了带参构造函数 给成员属性赋值 初始化列表也是类似 给成员属性赋值

区别:初始化列表可以给当前类属性赋值 以及对象成员赋值 (以及父类成员赋值)

基本初始化列表

类名(形参):类成员(形参)

class A
{
public:
    int m_A;
    int m_B;
    A(int a,int b):m_A(a),m_B(b)    //初始化列表  
           {}                       //格式 构造函数: 函数名(形参a,形参b):类属性1(形参a),类属性2(形参b)
};

void test_01()
{
    A a(10,20);
    cout<<a.m_A<<"  "<<a.m_B<<endl;    //10 20 
}

对象成员初始化列表

对象成员初始化列表

class B     //类成员
{
public:
    int m_C;    
    B(int c):m_C(c)    //需要写有参构造 或 初始化列表
    {}
};

class A
{
public:
    int m_A;
    int m_B;
    B ob;   //定义类成员
    A(int a,int b,int c):m_A(a),m_B(b),ob(c)    //ob(c)初始化列表初始化对象队成员
    {}
};

void test_01()
{
    A a(10,20,30);
    cout<<a.m_A<<"  "<<a.m_B<<"  "<<a.ob.m_C<<endl; //10 20 30
}

explicit关键字(了解)

该关键字禁止使用隐式转换调用构造函数

class A
{
public:
    int m_A;
    explicit A(int a):m_A(a)   //禁止隐式转换
    {
        cout<<"有参构造"<<endl;
    }
};

void test_01()
{
    //A a = 10;   //ERROR explicit关键字禁止隐式转换调用构造函数
    A a(10);
}

动态对象创建(new delete)

在C语言中提供了malloc函数对动态对象开辟空间 并使用free函数进行释放

然而这些函数在C++中不能很好的运行 因为它不能帮我们完成对象的初始化工作

主要问题:

程序必须确定对象的长度

malloc返回一个void指针 C++不允许将void赋值给其他任何指针,必须强转

在操作对象中 更需要使用new方式调用构造函数

结论:c的动态内存分配函数太复杂,容易令人混淆 是不可接受的 C++中我们推荐使用运算符new和delete来动态分配内存

new和delete

    //C的动态内存方式
    int *p1 = (int*)malloc(sizeof(int));
    *p1 = 5;

    //C++的动态内春方式
    int *p2 = new int;
    *p2 = 6;

    //简化方式
    int *p3 = new int(7);

    cout<<*p1<<"  "<<*p2<<"  "<<*p3<<endl;  //5  6  7

    //释放空间
    free(p1);
    delete p2;
    delete p3;

数组的创建

    int *arr1 = new int[5];
    cout<<arr1[0]<<"  "<<arr1[1]<<endl;   //随机值 因为没有初始化
    delete []arr1;  //释放空间 []arr1:数组

    int *arr2 = new int[5]{1,2,3,4,5};   //直接初始化
    cout<<arr2[0]<<"  "<<arr2[1]<<endl;
    delete []arr2;  //释放空间

对象的创建

    A *a1 = new A;   //自动调用无参构造
    delete a1;       //delete才会调用析构函数

    A *a2 = new A(10);  //自动调用有参构造
    delete a2;

对象数组的创建

class A
{
public:
    int m_A;
    A()
    {
        cout<<"无参构造"<<endl;
    }
    A(int a):m_A(a)
    {
        cout<<"有参构造"<<endl;
    }
    ~A()
    {
        cout<<"析构函数"<<endl;
    }
};

void test_01()
{
    A *arr = new A[3]{A(10),A(20),A(30)};
    //A *arr = new A[3]{10,20,30};    //也可以 使用隐式转换 但是不建议
    for(int i=0;i<3;i++)
    {
        cout<<arr[i].m_A<<"  "; //10  20  30
    }
    cout<<endl;
    delete []arr;
}

new的拷贝构造

前面学习了使用malloc进行拷贝构造 在C++中 真正的拷贝构造场景应该是通过new来进行拷贝构造

class Person
{
private:
    char *m_Name;
    int m_Age;
public:
    Person()
    {
        cout<<"无参构造"<<endl;
    }
    Person(char *name,int age)
    {
        m_Name = new char [strlen(name)+1];
        strcpy(m_Name,name);
        m_Age = age;
        cout<<"有参构造"<<endl;
    }
    Person(Person &p)
    {
        m_Name = new char [strlen(p.m_Name)+1];
        strcpy(m_Name,p.m_Name);
        m_Age = p.m_Age;
        cout<<"拷贝构造"<<endl;
    }
    ~Person()
    {
        if(m_Name == NULL)
        {
            delete m_Name;
            m_Name = NULL;
        }
        cout<<"析构函数"<<endl;
    }
};


void test_01()
{
    Person p1("zangsan",18);    //带参构造
    Person p2 = p1;             //拷贝构造
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值