C++构造函数和析构函数

限时加码!20+主流AI编程工具免费用 购周边加赠Coding Plan Lite,Claude Code、Cursor等即刻畅享,学习进阶更高效! 阅读详情

一、构造函数的介绍
    1. 构造函数的作用
        构造函数主要用来在创建对象时完成对对象属性的一些初始化等操作, 当创建对象时, 对象会自动调用它的构造函数。一般来说, 构造函数有以下三个方面的作用:
            ■ 给创建的对象建立一个标识符;
            ■ 为对象数据成员开辟内存空间;
            ■ 完成对象数据成员的初始化。
        
    2. 默认构造函数
        当用户没有显式的去定义构造函数时, 编译器会为类生成一个默认的构造函数, 称为 "默认构造函数", 默认构造函数不能完成对象数据成员的初始化, 只能给对象创建一标识符, 并为对象中的数据成员开辟一定的内存空间。
        
    3. 构造函数的特点
        无论是用户自定义的构造函数还是默认构造函数都主要有以下特点:
            ①. 在对象被创建时自动执行;
            ②. 构造函数的函数名与类名相同;
            ③. 没有返回值类型、也没有返回值;
            ④. 构造函数不能被显式调用。
            

        #给Python程序员的注释: C++中的构造函数类似于Python中的 __init__ 方法.


        
        
        
        
二、构造函数的显式定义
    由于在大多数情况下我们希望在对象创建时就完成一些对成员属性的初始化等工作, 而默认构造函数无法满足我们的要求, 所以我们需要显式定义一个构造函数来覆盖掉默认构造函数以便来完成必要的初始化工作, 当用户自定义构造函数后编译器就不会再为对象生成默认构造函数。
    
    在构造函数的特点中我们看到, 构造函数的名称必须与类名相同, 并且没有返回值类型和返回值, 看一个构造函数的定义:

复制代码
 1     #include <iostream>
 2 
 3     using namespace std;
 4 
 5     class Point
 6     {
 7         public:
 8             Point()     //声明并定义构造函数
 9             {
10                 cout<<"自定义的构造函数被调用...\n";
11                 xPos = 100;         //利用构造函数对数据成员 xPos, yPos进行初始化
12                 yPos = 100;
13             }
14             void printPoint()
15             {
16                 cout<<"xPos = " << xPos <<endl;
17                 cout<<"yPos = " << yPos <<endl;
18             }
19 
20         private:
21             int xPos;
22             int yPos;
23     };
24 
25     int main()
26     {
27         Point M;    //创建对象M
28         M.printPoint();
29 
30         return 0;
31     }
复制代码

 
    编译运行的结果:

复制代码
        自定义的构造函数被调用...
        xPos = 100
        yPos = 100

        Process returned 0 (0x0)   execution time : 0.453 s
        Press any key to continue.
复制代码

 


    代码说明:
        在Point类的 public 成员中我们定义了一个构造函数 Point() , 可以看到这个Point构造函数并不像 printPoint 函数有个void类型的返回值, 这正是构造函数的一特点。在构造函数中, 我们输出了一句提示信息, "自定义的构造函数被调用...", 并且将对象中的数据成员xPos和yPos初始化为100。
        
        在 main 函数中, 使用 Point 类创建了一个对象 M, 并调用M对象的方法 printPoint 输出M的属性信息, 根据输出结果看到, 自定义的构造函数被调用了, 所以 xPos和yPos 的值此时都是100, 而不是一个随机值。
        
        需要提示一下的是, 构造函数的定义也可放在类外进行。
        
        
        


        
三、有参数的构造函数
    在上个示例中实在构造函数的函数体内直接对数据成员进行赋值以达到初始化的目的, 但是有时候在创建时每个对象的属性有可能是不同的, 这种直接赋值的方式显然不合适。不过构造函数是支持向函数中传入参数的, 所以可以使用带参数的构造函数来解决该问题。
    

复制代码
 1     #include <iostream>
 2 
 3     using namespace std;
 4 
 5     class Point
 6     {
 7         public:
 8             Point(int x = 0, int y = 0)     //带有默认参数的构造函数
 9             {
10                 cout<<"自定义的构造函数被调用...\n";
11                 xPos = x;         //利用传入的参数值对成员属性进行初始化
12                 yPos = y;
13             }
14             void printPoint()
15             {
16                 cout<<"xPos = " << xPos <<endl;
17                 cout<<"yPos = " << yPos <<endl;
18             }
19 
20         private:
21             int xPos;
22             int yPos;
23     };
24 
25     int main()
26     {
27         Point M(10, 20);    //创建对象M并初始化xPos,yPos为10和20
28         M.printPoint();
29 
30         Point N(200);       //创建对象N并初始化xPos为200, yPos使用参数y的默认值0
31         N.printPoint();
32 
33         Point P;            //创建对象P使用构造函数的默认参数
34         P.printPoint();
35 
36         return 0;
37     }
复制代码

 
    编译运行的结果:

复制代码
        自定义的构造函数被调用...
        xPos = 10
        yPos = 20
        自定义的构造函数被调用...
        xPos = 200
        yPos = 0
        自定义的构造函数被调用...
        xPos = 0
        yPos = 0

        Process returned 0 (0x0)   execution time : 0.297 s
        Press any key to continue.
复制代码

 


    代码说明:
        在这个示例中的构造函数 Point(int x = 0, int y = 0) 使用了参数列表并且对参数进行了默认参数设置为0。在 main 函数中共创建了三个对象 M, N, P。
            M对象不使用默认参数将M的坐标属性初始化10和20;
            N对象使用一个默认参数y, xPos属性初始化为200;
            P对象完全使用默认参数将xPos和yPos初始化为0。

            
            


            
三、构造函数的重载
    构造函数也毕竟是函数, 与普通函数相同, 构造函数也支持重载, 需要注意的是, 在进行构造函数的重载时要注意重载和参数默认的关系要处理好, 避免产生代码的二义性导致编译出错, 例如以下具有二义性的重载:
    

复制代码
        Point(int x = 0, int y = 0)     //默认参数的构造函数
        {
            xPos = x;
            yPos = y;
        }

        Point()         //重载一个无参构造函数
        {
            xPos = 0;
            yPos = 0;
        }
复制代码

        
    在上面的重载中, 当尝试用 Point 类重载一个无参数传入的对象 M 时, Point M; 这时编译器就报一条error: call of overloaded 'Point()' is ambiguous 的错误信息来告诉我们说 Point 函数具有二义性, 这是因为 Point(int x = 0, int y = 0) 全部使用了默认参数, 即使我们不传入参数也不会出现错误, 但是在重载时又重载了一个不需要传入参数了构造函数 Point(), 这样就造成了当创建对象都不传入参数时编译器就不知道到底该使用哪个构造函数了, 就造成了二义性。
    
    
    

 


四、初始化表达式
    对象中的一些数据成员除了在构造函数体中进行初始化外还可以通过调用初始化表来进行完成, 要使用初始化表来对数据成员进行初始化时使用 : 号进行调出, 示例如下:
    

        Point(int x = 0, int y = 0):xPos(x), yPos(y)  //使用初始化表
        {
            cout<<"调用初始化表对数据成员进行初始化!\n";
        }

        
    在 Point 构造函数头的后面, 通过单个冒号 : 引出的就是初始化表, 初始化的内容为 Point 类中int型的 xPos 成员和 yPos成员, 其效果和 xPos = x; yPos = y; 是相同的。
    
    与在构造函数体内进行初始化不同的是, 使用初始化表进行初始化是在构造函数被调用以前就完成的。每个成员在初始化表中只能出现一次, 并且初始化的顺序不是取决于数据成员在初始化表中出现的顺序, 而是取决于在类中声明的顺序。
    
    此外, 一些通过构造函数无法进行初始化的数据类型可以使用初始化表进行初始化, 如: 常量成员和引用成员, 这部分内容将在后面进行详细说明。使用初始化表对对象成员进行初始化的完整示例:
    

复制代码
 1     #include <iostream>
 2 
 3     using namespace std;
 4 
 5     class Point
 6     {
 7         public:
 8             Point(int x = 0, int y = 0):xPos(x), yPos(y)
 9             {
10                 cout<<"调用初始化表对数据成员进行初始化!\n";
11             }
12 
13             void printPoint()
14             {
15                 cout<<"xPos = " << xPos <<endl;
16                 cout<<"yPos = " << yPos <<endl;
17             }
18 
19         private:
20             int xPos;
21             int yPos;
22     };
23 
24     int main()
25     {
26         Point M(10, 20);    //创建对象M并初始化xPos,yPos为10和20
27         M.printPoint();
28 
29         return 0;
30     }
复制代码

 



    


    
五、析构函数
    与构造函数相反, 析构函数是在对象被撤销时被自动调用, 用于对成员撤销时的一些清理工作, 例如在前面提到的手动释放使用 new 或 malloc 进行申请的内存空间。析构函数具有以下特点:
        ■ 析构函数函数名与类名相同, 紧贴在名称前面用波浪号 ~ 与构造函数进行区分, 例如:~Point();
        ■ 构造函数没有返回类型, 也不能指定参数, 因此析构函数只能有一个, 不能被重载;
        ■ 当对象被撤销时析构函数被自动调用, 与构造函数不同的是, 析构函数可以被显式的调用, 以释放对象中动态申请的内存。

 

    #给Python程序员的注释: C++中的析构函数类似于Python中的 __del__ 方法.

 


    当用户没有显式定义析构函数时, 编译器同样会为对象生成一个默认的析构函数, 但默认生成的析构函数只能释放类的普通数据成员所占用的空间, 无法释放通过 new 或 malloc 进行申请的空间, 因此有时我们需要自己显式的定义析构函数对这些申请的空间进行释放, 避免造成内存泄露。

复制代码
 1 #include <iostream>
 2      #include <cstring>
 3 
 4      using namespace std;
 5 
 6      class Book
 7      {
 8          public:
 9              Book( const char *name )      //构造函数
10              {
11                  bookName = new char[strlen(name)+1];
12                  strcpy(bookName, name);
13              }
14              ~Book()                 //析构函数
15              {
16                  cout<<"析构函数被调用...\n";
17                  delete []bookName;  //释放通过new申请的空间
18              }
19              void showName() { cout<<"Book name: "<< bookName <<endl; }
20 
21          private:
22              char *bookName;
23      };
24 
25      int main()
26      {
27          Book CPP("C++ Primer");
28          CPP.showName();
29 
30          return 0;
31 
32      }
复制代码


    编译运行的结果:

        Book name: C++ Primer
        析构函数被调用...

        Process returned 0 (0x0)   execution time : 0.266 s
        Press any key to continue.


    代码说明:
        代码中创建了一个 Book 类, 类的数据成员只有一个字符指针型的 bookName, 在创建对象时系统会为该指针变量分配它所需内存, 但是此时该指针并没有被初始化所以不会再为其分配其他多余的内存单元。在构造函数中, 我们使用 new 申请了一块 strlen(name)+1 大小的空间, 也就是比传入进来的字符串长度多1的空间, 目的是让字符指针 bookName 指向它, 这样才能正常保存传入的字符串。
        
        在 main 函数中使用 Book 类创建了一个对象 CPP, 初始化 bookName 属性为 "C++ Primer"。从运行结果可以看到, 析构函数被调用了, 这时使用 new 所申请的空间就会被正常释放。
        
        自然状态下对象何时将被销毁取决于对象的生存周期, 例如全局对象是在程序运行结束时被销毁, 自动对象是在离开其作用域时被销毁。 
        
    如果需要显式调用析构函数来释放对象中动态申请的空间只需要使用 对象名.析构函数名(); 即可, 例如上例中要显式调用析构函数来释放 bookName 所指向的空间只要:

        CPP.~Book();
析构函数的初学 一.什么是析构函数 1.名字类名相同,在前面加‘~’,没有参数返回值,一个类最多只能有一个析构函数 2.析构函数对象消亡时即自动被调用。可以定义析构函数来在对象消亡前做善后工作,比 如释放分配的空间等 3.如果定义类时没写析构函数,则编译器自动生成缺省析构函数。缺省析构函数什么也不做 #include<iostream> using namespace std; class A { public: A() { cout&lt... 阅读详情

相关推荐

C++——构造函数析构函数、new对象

简单来说,有对象生成必然会调用构造函数,有对象销毁必然会调用析构函数构造函数的作用是成员变量,是由编译器去调用的,而析构函数同理也是由编译器调用,不过他的作用则是。可以由下面的代码体验两个函数的使用。注意:相同点:两个函数都没有返回值,不能用void不同点:构造函数可以有参数,析构函数没有参数运行结果:1. 构造函数可以重载2.当构造函数私有时,无法实例化对象,所以构造函数析构函数都是公有的补充:实例化对象的时候内部操作:1.分配空间(将对象m分配到栈区)2.调用构造函数进行初始化。

immnature的博客 2176

析构函数详解

析构函数详解 析构函数的概念 前面通过构造函数的学习,我们知道一个对象是怎么来的,那一个对象又是怎么没呢的? 析构函数:与构造函数功能相反,析构函数是完成对象的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成类的一些资源清理工作。 析构函数用来完成对象资源清理的工作 析构函数的特性 析构函数名是在类名前加上字符 ~。 无参数无返回值。 一个类有且只有一个析构函数。若用户没有显式定义,系统会自动生成默认的析构函数。 当对象生命周期结束时,C++编译系统系统会自动调用析构函数

weixin_43831728的博客 2万+

Librepilot _64位window10环境下的搭建及一些坑的解决办法

  刚入IT行业的小菜鸟,在window上折腾了四天的librepilot地面控制站的搭建,想着这么辛苦不能白费了,看网上相关资料少得可怜,唯一一个详细教程还是在32位环境下,一大堆坑,所以把自己的经验写下来,供大家一起参考。 参考的原文是:https://www.cnblogs.com/jasonchan1202/p/7809937.html的博客,但是执行下来才发现这个博客对64位系统极其不...

weixin_41426339的博客 2707

学习C++ -> 构造函数析构函数

学习C++ -&gt; 构造函数析构函数   一、构造函数的介绍    1. 构造函数的作用        构造函数主要用来在创建对象时完成对对象属性的一些初始化等操作, 当创建对象时, 对象会自动调用它的构造函数。一般来说, 构造函数有以下三个方面的作用:            ■ 给创建的对象建立一个标识符;            ■ 为对象数据成员开辟内存空间;            ...

weixin_34050519的博客 184

第十一周:类 + 构造 + 析构 + 复制构造

1.CPU类设计 题目: 声明一个CPU类,包含等级(rank)、频率(frequency)、电压(voltage)等私有属性,有两个公有成员函数run、stop。其中,rank为枚举类型CPU_Rank,声明为enum CPU_Rank{P1=1,P2,P3,P4,P5,P6,P7};frequency为单位是MHz的整型数,vlotage为浮点型的电压值。 (1)分别编写不同的Set函数Get函数修改、获取私有数据成员,例如void SetRank(CPU_Rank cr);CPU_Rank GetR

一只可爱的小猴子的博客 1802

C++学习——构造函数析构函数

C++中有一种特殊的成员函数,它的名字类名相同,可以有形参,但没有返回值,不需要用户显式调用(用户也不能调用),而是在创建对象时自动执行。这种特殊的成员函数就是构造函数(Constructor)。析构函数(Destructor)是一种特殊的成员函数,它的名字是在类名前面加一个符号,没有返回值,没有参数,不需要程序员显式调用(程序员也没法显式调用),而是在销毁对象时自动执行。

主要记录嵌入式学习与开发过程。 6061

C++ 构造函数析构函数 详解

C++中用构造函数析构函数来初始化清理对象,这两个函数将会被编译器自动调用。对象的初始化清理是非常重要的,如果我们不提供构造函数析构函数,编译器会自动提供两个函数的空实现。............

a只如初见的博客 3万+

C++】:构造函数析构函数

如果一个类中什么成员都没有,简称为空类。空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。默认成员函数用户没有显式实现,编译器会生成的成员函数称为默认成员函数。这篇文章介绍的是构造函数析构函数。1.一般情况下构造函数都需要我们自己显式的去实现。2.只有少数情况下可以让编译器自动生成构造函数。(类似用两个栈实现队列的MyQueue,它的成员都是自定义类型)

2301_77900444的博客 4514

C++C++中的构造函数析构函数详解

本篇主题为:C++中的构造函数析构函数详解写在前头:本篇会从类的六个默认成员函数开始,进入构造函数析构函数的研究。

cilmy23的note 7798

C/Cpp / C++ 构造函数析构函数可以是虚函数吗

答案 构造函数不可以是虚函数,而析构函数可以且常常是虚函数。 原因 1、构造函数不可以是虚函数 当类中声明虚函数时,编译器会在类中生成一个虚函数表,虚函数表是一个存储成员函数指针的数据结构。 虚函数表是由编译器自动生成与维护的,virtual成员函数会被编译器放入虚函数表中,当存在虚函数时,每个对象都有一个指向虚函数的指针(vptr指针)。在实现多态的过程中,父类派生类都有vptr指针。 vptr的初始化:当对象在创建时,由编译器对 vptr 指针进行初始化。在定义子类对象时,vptr 先指向

布袋和尚 1246

C++构造函数析构函数的总结

C++是面向对象的编程语言,在定义类的时候,离不开构造析构函数。类中同类同名的成员函数称为构造函数,主函数中初始化一个对象时,如果有传入数据,其实是传入到构造函数的形参中。

ladybai的博客 1万+

C++构造函数析构函数

【代码】C++构造函数析构函数

物是人非,结局始终不美 2万+

C++——构造函数析构函数

构造函数析构函数

2301_79310249的博客 1236

c++构造函数析构函数

一、构造函数析构函数的特点 构造函数析构函数是一种特殊的公有成员函数,每一个类都有一个默认的构造函数析构函数构造函数在类定义时由系统自动调用,析构函数在类被销毁时由系统自动调用; 构造函数的名称类名相同,一个类可以有多个构造函数,只能有一个析构函数。不同的构造函数之间通过参数个数参数类型来区分; 我们可以在构造函数中给类分配资源,在类的析构函数中释放对应的资源。 二、不带参数的构造函数 C++类在创建时,系统会默认创建一个不带参数的构造函数,我们可以重新定义这个构造函数。默认构造函数在类被

weixin_39270987的博客 1万+

C++ 类(构造函数析构函数)

文章概述 构造函数析构函数的由来? 构造函数析构函数的基本语法 C++编译器构造析构方案 PK 对象显示初始化方案 构造函数的分类以及调用 默认的构造函数 构造函数调用规则 构造函数析构函数的总结 构造函数析构函数的由来 类的数据成员不能在类的声明时候初始化,为了解决这个问题? 使用构造函数处理对对象的初始化。构造函数是一种特殊的成员函数,与其他函数不同,不需要用户调用它,而...

小白的博客 5万+

【Cpp】类对象#构造函数 析构函数

但是st1的类没有写析构函数,也只是调用默认生成的析构,这时,st1中的动态申请的堆空间就无法释放了,造成内存泄漏)默认生成虽然好,但是如果默认生成的构造/析构函数在调用时由于只处理自定义类型,如果自定义类型的构造/析构没有写,那么即使是默认生成的函数,本质上也是没有做任何工作。构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象,而是初始化对象。与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由编译器完成的。

石墨博客 1411

C++ 构造函数析构函数可以是虚函数嘛?

简单总结就是:构造函数不可以是虚函数,而析构函数可以且常常是虚函数。 构造函数不能是虚函数 1. 从vptr角度解释 虚函数的调用是通过虚函数表来查找的,而虚函数表由类的实例化对象的vptr指针(vptr可以参考C++的虚函数表指针vptr)指向,该指针存放在对象的内部空间中,需要调用构造函数完成初始化。如果构造函数是虚函数,那么调用构造函数就需要去找vptr,但此时vptr还...

Magnum的博客 1万+

C++构造函数析构函数

构造函数是特殊的公有成员函数(但不是只是公有成员函数,在特殊用途中构造函数的访问限定可以定义为私有或保护)。函数名称与类同名:构造函数名称必须与类名严格一致。无返回值类型:无需声明返回类型(是没有返回类型,而不是void),实际上构造函数有返回值,返回值就是构造函数所创建的对象。在程序运行时,当新的对象被建立,该对象所属的类构造函数自动被调用,在该对象的生存周期中也只调用这一次。

2302_76793428的博客 1289

入门cpp之构造函数析构函数

int _month;int _day;对于上面这个类,我们每次创建一个Date类型的变量,都需要调用Init函数去初始化,难免会有忘记初始的时候。cpp中有构造函数可以在变量创建时,自动将信息设置进去,这就是构造函数构造函数是一个特殊的成员函数,名字与类名相同创建类类型对象时由编译器自动调用,以保证每个数据成员都有一个合适的初始值,并且在对象整个生命周期内只调用一次。

zyzyzy_mhmhmh的博客 825
上一篇: c,c++中const的用法
下一篇: C++中成员变量的初始化
YiLe君
博客等级 码龄15年 9粉丝 3原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值