千家信息网

C++的构造函数和析构函数是哪个

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,这篇文章主要讲解了"C++的构造函数和析构函数是哪个",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"C++的构造函数和析构函数是哪个"吧!一、构造函数首
千家信息网最后更新 2026年11月03日C++的构造函数和析构函数是哪个

这篇文章主要讲解了"C++的构造函数和析构函数是哪个",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"C++的构造函数和析构函数是哪个"吧!

    一、构造函数

    首先,由于类只是一个模板,因此我们在定义类时无法对成员变量初始化,比如下面代码就是错误的:

    class circle{public:    int m_L = 20;    // Error:不允许使用数据成员初始值设定项};

    因此,初始化只能发生在类创建对象的过程中,但是由于访问权限的原因,无法在类外访问某些成员变量,因此下面这种做法有时候是无效的:

    circle C1;     // 实例化一个对象 C1C1.m_L = 20;  // 通过创建的对象,来给对应变量初始化,但是如果m_L是private访问权限,则失效

    为了解决这个问题,让程序员能像使用标准数据类型一样适用对象,在类内提供了一个特殊的成员函数--"构造函数",专门用于在创建对象时初始化类对象。之所以说它特殊,是因为C++已经自动为构造函数提供了名称和使用语法,程序员只需要提供方法的定义即可,即:类名(形参列表)。具体来说,构造函数的定义如下:

    class circle{public:    int m_L;public: //成员函数(方法)    circle(const int a)   //通过构造函数对成员变量进行赋值    {        m_L = a;    }};circle C1(20);     //调用格式cout << "C1.m_L:" << C1.m_L <

    看上去似乎很简单,但是由于构造函数也是函数,因此所有C++中的形参传递方式,函数特性以及函数调用方法都能用于构造函数。 如前文所讲,C++会自动给类添加一个空的构造函数,但是如果自己在类中实现了有参构造函数,编译器便不再提供无参构造函数。举例如下:

    class circle{public:    int m_L;public: //成员函数(方法)    circle(const int a)   //通过构造函数对成员变量进行赋值    {        m_L = a;    }};circle C1(20);     //调用格式正确,能够通过构造函数赋值circle C2;            //错误,自己定义了有参构造函数,不再提供无参构造函数

    构造函数可以重载,接着上面的例子,如果重载一个空的构造函数,那么两个调用格式都正确:

    class circle{public:    int m_L;public: //成员函数(方法)    circle(){}      // 空构造函数    circle(const int a)   //通过构造函数对成员变量进行赋值    {        m_L = a;    }};circle C1(20);     //调用格式正确,能够通过构造函数赋值circle C2;            //正确,可以通过重载的空构造函数实现初始化

    构造函数的参数不仅可以是标准数据类型,也可以是类。众所周知,在数值作为函数参数进行传递的时候,会重新拷贝出来一份数据作为参数传递用完即销毁,这种方式不仅浪费了内存空间,而且无法修改原始数据。为了结合这两者之间的优点,于是经常采取引用作为函数的参数。虽然引用是指针的一种特殊情况,但是指针太过于灵活,并且引用在形式上引用与普通的变量地用法并没有什么区别,因此使用起来更加方便。

    class circle{public:    int m_L;public: //成员函数(方法)    circle(){}      // 空构造函数    circle(const int a)   //通过构造函数对成员变量进行赋值    {        m_L = a;    }    //引用作为函数参数传递,并用const修饰,节省空间的同时避免修改原数据    circle(const circle& sub_circle)      {        m_L = sub_circle.m_L;    }};circle C1(20);     //调用格式正确,能够通过构造函数赋值circle C2(C1);        //正确,可以通过拷贝构造函数进行初始化

    二、C++类的内存模型

    C++中,一个类包括:

    • 成员变量:静态成员变量和普通成员变量

    • 成员函数:静态成员函数和普通成员函数

    虽然为了集成,我们将其写到一个类里面,但是只有普通成员变量真正属于类的对象,类的所有对象共享一份静态成员函数,静态成员变量和普通成员函数。画出了内存模型,如下图所示:

    为了进一步理解,我们举例如下:

    2.1、只定义成员函数

    class person{public:    // 定义一个空的构造函数        person(int m_age, int m_ID){        }};person p1(10, 20);cout << "p1 所占的空间为:" << sizeof(p1) << endl;

    输出结果为:

    p1 所占的空间为:1

    这个题目在《剑指offer》一书中也提到过,由空类实例化出来的对象所占的内存空间是1个而不是0个字节,因为编译其给对象 p1 分配了一个地址,来表示不同的对象存储在不同的地址空间,因此占用1个字节。

    2.2、往空类中添加静态成员变量

    class person{    static int age; //静态成员变量,存在全局区,不属于类对象的一部分    static int ID;  //静态成员变量,存在全局区,不属于类对象的一部分public:    // 定义一个空的构造函数        person(int m_age, int m_ID){        }};person p1(10, 20);cout << "p1 所占的空间为:" << sizeof(p1) << endl;

    输出结果为:

    p1 所占的空间为:1

    当向类中加入了成员函数与静态成员变量时,类的实例化对象仍然只占用1个字节的空间,足以证明这些函数和变量并不是类对象的一部分。

    2.3、再加入非静态成员变量

    class person{    static int age; //静态成员变量,存在全局区,不属于类对象的一部分    static int ID;  //静态成员变量,存在全局区,不属于类对象的一部分    int a;     //非静态成员变量,存在栈区,属于类对象的一部分public:        person(int m_age, int m_ID){        }};

    输出结果为:

    p 所占的空间为:4

    因此当向类中加入了非静态成员变量时,类的实例化对象占用4个字节的空间,可以说明,非静态变量属于类对象的一部分。综上:同一个类所有实例化出来的对象共享同一份静态成员变量,所以一改全改。既然同一个类的不同对象共享同一份成员函数,那么成员函数怎么区分该访问哪个对象的普通成员变量呢?

    三、this指针

    接着上一小节的问题,this指针为上述问题提供了一个完美的解决方案,它指向用来调用成员函数的对象(被当作参数隐式地传递给成员函数),我们通过一张图来理解它:

    此外,this指针的另一个用途是当成员函数需要返回对象时,用 return *this; 或者 return this,这种做法能够实现链式编程。比如:

    p2.addPerson(p1).addPerson(p1);

    首先,对象 p2 调用成员函数 addPerson(p1) ,其返回值继续调用 addPerson(p1),此时返回值就必须也是 person 类型才可以,因此使用 this 指针可以完成需求。先来看第一个例子:

    class person{public:        int age;        person(int age)        {                this->age = age; // this指针区分调用者        }        // 返回值为person类型,且参数加上了const限制,防止修改原数据        person addPerson(const person& p)        {                this->age += p.age;        // 主要实现两个类对象年龄的相加                return *this;      // 由于返回值是person,因此返回 *this        }};person p1(20);person p2(10);person p3 = p2.addPerson(p1).addPerson(p1);cout << "p1 age:" << p1.age << endl;cout << "p2 age:" << p2.age << endl;cout << "p3 age:" << p3.age << endl;

    首先,通过构造函数分别对 p1,p2 赋了初值,然后 p2 调用函数 addPerson(p1) 修改自身的变量 age 。**由于函数通过值传递的方式返回 person 类型,所以将整个 person 类型复制了一份返回,返回值继续调用 addPerson(p1), **最后的结果赋值给了新的对象 p3。所以输出结果为:

    p1 age:20

    p2 age:30

    p3 age:50

    但是如果函数 addPerson() 修改为:

    person& addPerson(const person& p){    this->age += p.age;        // 主要实现两个类对象年龄的相加    return *this;      // 虽然返回值是person&,返回值的类型也是 *this}person p1(20);person p2(10);person p3 = p2.addPerson(p1).addPerson(p1);cout << "p1 age:" << p1.age << endl;cout << "p2 age:" << p2.age << endl;cout << "p3 age:" << p3.age << endl;

    与上例唯一的区别就在于返回值的类型变成了引用,那么每次返回的就变成了该对象本身,而非在值传递中拷贝出来的那一份数据。那么输出就变成了:

    p1 age:20

    p2 age:50

    p3 age:50

    四、析构函数

    用构造函数创建对象后,程序负责跟踪该对象,知道其过期为止。当对象过期时,程序自动调用析构函数完成清理工作。与构造函数一样,C++默认提供了一个空的析构函数,定义为:~类名( )。由于开辟在栈区的变量程序会自动释放,因此不需要析构函数执行清理工作,但是当程序员在堆区开辟空间时,需要手动执行清理工作,这时候需要析构函数来释放堆区内存。比如:

    ~person(){        // 在析构函数内写入需要执行的代码        cout << "调用析构函数" << endl;}person p1(20);person p2(10);     // 在生命周期结束后自动调用析构函数执行清理工作

    输出为:

    调用析构函数

    调用析构函数

    感谢各位的阅读,以上就是"C++的构造函数和析构函数是哪个"的内容了,经过本文的学习后,相信大家对C++的构造函数和析构函数是哪个这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

    函数 成员 对象 变量 静态 空间 C++ 数据 类型 参数 指针 普通 方法 程序 输出 内存 实例 格式 结果 全局 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 科技互联网 互联网高科技 伟宏互联网科技 上海睿民互联网科技有限公司 互联网科技产业 北京互联网科技 上海挚品互联网科技 互联网科技股票 易通互联网络科技有限公司 互联网科技公司做什么 科技大学互联网专业好不好 河南猎农互联网科技有限公司 南平创想时代互联网科技有限公司 崇明区互联网教育科技售后服务 哈尔滨屹滨互联网科技有限公司 伍佰万互联网科技怎么赚钱 风投北京互联网科技 安徽零酒互联网科技有限公司 伍佰万互联网科技是干嘛的 株洲百竞科技的互联网营销顾问 互联网是不是新科技 华宇互联网科技 未来的互联网科技 齐家互联网科技有限公司 青岛中康互联网医疗科技有限公司 厦门比较好的科技互联网公司 洛阳昕诺飞互联网科技有限公司 佛山市翊博互联网络科技有限公司 城市宝互联网科技有限公司 北京品多多互联网科技有限公司
    0