对象的构造和析构

目录

构造函数和析构函数

构造函数的分类和调用

c++默认构造的函数

浅拷贝和深拷贝

多个对象的构造和析构

初始化列表

类对象作为成员


构造函数和析构函数

对象的初始化和清理是两个非常重要的安全问题,一个对象或者变量没有初始时,对其使用后果是未知,同样的使用完一个变量,没有及时清理,也会造成一定的安全问题。c++为了给我们提供这种问题的解决方案,构造函数和析构函数,这两个函数将会被编译器自动调用,完成对象初始化和对象清理工作。
构造函数主要作用在于 创建对象 时为对象的成员属性赋值
析构函数主要用于 对象销毁 前系统自动调用,执行一些清理工作。
#include <iostream>
#include <string.h>

using namespace std;

class function
{
    public:
        //构造函数 函数名和类名相同,没有返回值,不能有void,但可以有参数 可以重载
        function(int init_age,string init_name)
        {
            age = init_age;
            name = init_name;
            cout << "构造函数调用" << endl;
        }
        //析构函数 函数名是在类名前面加”~”组成,没有返回值,不能有void,不能有参数,不能重载
        ~function()
        {
            cout << "析构函数调用" << endl;
        }
    public:
        int age;
        string name;
};

void test()
{
    function p1(10,"lucy");//构造函数在实例化对象时会创建,就是在内存开辟空间时会被调用
    //定义在栈区 test生命周期结束后会被销毁 在销毁之前自动调用析构函数 
}

int main()
{
    test();
    return 0;
}

编译运行

构造函数的分类和调用

按参数类型:分为无参构造函数和有参构造函数

按类型分类:普通构造函数和拷贝构造函数(复制构造函数)

拷贝构造:拷贝构造的调用时机:旧对象初始化新对象

                  其形参必须是引用,但并不限制为const,一般普遍的会加上const限制

                  如果自定义了一个拷贝构造 那么系统不再提供默认的拷贝构造

#include <iostream>
#include <string.h>

using namespace std;

class function
{
    public:  
        function()
        {
            cout << "无参构造函数" << endl;
        }

        function(int init_age,string init_name)
        {
            age = init_age;
            name = init_name;
            cout << "有参构造函数" << endl;
        }
        //拷贝构造的调用时机:旧对象初始化新对象
        //如果自定义了一个拷贝构造 那么系统不再提供默认的拷贝构造
        function(const function &p)//不能写function p 不能产生新对象 
        {
            //拷贝构造做了简单的值拷贝
            age = p.age;
            name = p.name;
            cout << "拷贝构造" << endl;
        }
        ~function()
        {
            cout << "析构" << endl;
        }

    public:
        int age;
        string name;
};

void test01()
{
    //如果人为提供了一个有参或无参构造 系统将不再提供默认的无参构造
    function p1;//调用无参构造时 不能加括号
    function p2(10,"lucy");
    function p3(p2);//调用系统提供的默认拷贝构造
}

void test02()
{
    //匿名对象 没有名字 生命周期在当前行
    function (10,"tom");
    function ();
    function p1(20,"ben");
    //function p2(p); //匿名对象不能使用括号法调用拷贝函数
}
//显示法调用构造函数
void test03()
{
    function p1 =  function (10,"tom");//显示法调用有参函数 
    function p2 =  function (p1); //显示法调用拷贝函数
    function p3 =  function ();//显示法调用无参函数

}

int main()
{
    test();
    return 0;
}

c++默认构造的函数

默认情况下,c++编译器至少为我们写的类增加 3 个函数

1.默认构造函数(无参,函数体为空)

2.默认析构函数(无参,函数体为空)

3.默认拷贝构造函数,对类中非静态成员属性简单值拷贝

如果用户定义拷贝构造函数, c++ 不会再提供任何默认构造函数
如果用户定义了普通构造 ( 非拷贝 ) c++ 不在提供默认无参构造,但是会提供默认拷贝构造

浅拷贝和深拷贝

浅拷贝:同一类型的对象之间可以赋值,使得两个对象的成员变量的值相同,两个对象仍然是独立的两个对象,这种情况 被称为浅拷贝. 一般情况下,浅拷贝没有任何副作用,但是当类中有指针,并且指针指向动态分配的内存空间,析构函数做了动 态内存释放的处理,会导致内存问题。

深拷贝:当类中有指针,并且此指针有动态分配空间,析构函数做了释放处理,往往需要自定义拷贝构造函数,自行给指针动态分配空间。

class Person{
    public:
        Person(char* name,int age){
            pName = (char*)malloc(strlen(name) + 1);
            strcpy(pName,name);
            mAge = age;
        }
        //增加拷贝构造函数
        Person(const Person& person){
            pName = (char*)malloc(strlen(person.pName) + 1);//重新开辟空间
            strcpy(pName, person.pName);
            mAge = person.mAge;
        }
        ~Person(){
            if (pName != NULL){
                free(pName);
            }
        }
    private:
        char* pName;
        int mAge;
};
void test(){
    Person p1("Edward",30);
    //用对象 p1 初始化对象 p2,调用 c++提供的默认拷贝构造函数
    Person p2 = p1;
}

多个对象的构造和析构

初始化列表

构造函数和其他函数不同,除了有名字,参数列表,函数体之外还有初始化列表。
初始化列表简单使用 :
class Person{
public :
        //传统方式初始化
        Person(int a,int b,int c)
        {
        mA = a;
        mB = b;
        mC = c;
        }
        //初始化列表方式初始化
        //先声明再根据声明的顺序定义初始化
        Person( int a, int b, int c):mA(a),mB(b),mC(c){}
        void PrintPerson()
        {
        cout << "mA:" << mA << endl;
        cout << "mB:" << mB << endl;
        cout << "mC:" << mC << endl;
        }
        private :
        int mA;
        int mB;
        int mC;
};

类对象作为成员

类中有多个对象时,构造的顺序是先构造里面的对象,再构造外面的对象

类中有多个对象时,析构的顺序是先析构外面的对象,再析构外面的对象

class Car{
    public:
        Car(){
            cout << "Car 默认构造函数!" << endl;
            mName = "大众汽车";
        }
        Car(string name){
            cout << "Car 带参数构造函数!" << endl;
            mName = name;
        }
        ~Car(){
            cout << "Car 析构函数!" << endl;
        }
    public:
        string mName;
};
//拖拉机
class Tractor{
    public:
        Tractor(){
            cout << "Tractor 默认构造函数!" << endl;
            mName = "爬土坡专用拖拉机";
        }
        Tractor(string name){
            cout << "Tractor 带参数构造函数!" << endl;
            mName = name;
        }
        ~Tractor(){
            cout << "Tractor 析构函数!" << endl;
        }
    public:
        string mName;
};
//人类
class Person{
    public:
        //类 mCar 不存在合适的构造函数
        Person(string name){
            mName = name;
        }
        //初始化列表可以指定调用构造函数
        Person(string carName, string tracName, string name) : mTractor(tracName),
        mCar(carName), mName(name){
            cout << "Person 构造函数!" << endl;
        }
#endif
        void GoWorkByCar(){
            cout << mName << "开着" << mCar.mName << "去上班!" << endl;
        }
        void GoWorkByTractor(){
            cout << mName << "开着" << mTractor.mName << "去上班!" << endl;
        }
        ~Person(){
            cout << "Person 析构函数!" << endl;
        }
    private:
        string mName;
        Car mCar;
        Tractor mTractor;
};
void test(){
    //Person person("宝马", "东风拖拉机", "赵四");
    Person person("刘能");
    person.GoWorkByCar();
    person.GoWorkByTractor();
}

猜你喜欢

转载自blog.csdn.net/2301_77164542/article/details/132754037
今日推荐