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

news2024/11/19 15:24:49

(一)构造函数

  要点

  • 定义:构造函数 ,是一种特殊的方法。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。特别的一个类可以有多个构造函数 ,可根据其参数个数的不同或参数类型的不同来区分它们 即构造函数的重载。

  • 声明语法:

    派生类::派生类名(参数表):基类名1(基类1初始化参数列表),...,基类名n(基类n初始化参数列表),成员对象名1(成员对象1初始化参数表),...,成员对象名m(成员对象m初始化参数表),基本类型成员初始化

    {

       派生类构造函数的其他初始化操作;

    }
    构造函数的初始化参数列表: 构造函数名(参数1,参数2,...):成员1(参数1),成员2(参数2)....{}

  • 构造函数名字和类名相同

  • 构造函数没有返回值

  • 不写构造函数,每一个类中都存在默认的构造函数,默认的构造函数是没有参数

    • default显示使用默认的构造函数

    • delete 删掉默认函数

    • 当我们自己写了构造函数,默认的构造函数就不存在

  • 构造函数不需要自己调用,在构造对象的时候自己调用

    • 构造函数决定的了对象的长相

    • 无参构造函数可以构造无参对象

    • 有参构造函数,对象必须要带有参数

  • 构造函数允许被重载和缺省

  • 构造函数一般情况是公有属性

  • 构造函数一般是用来给数据成员初始化

  • 构造函数允许调用另个构造函数,必须采用初始化参数列表的写法

  •  派生类构造函数执行的一般顺序如下:

    • (1)调用基类构造函数,调用顺序按照它们被继承时声明的顺序(从左向右)。 

    • (2)对派生类新增的成员初始化,初始化顺序按照它们在类中声明的顺序 

    • (3)执行派生类的构造函数体中的内容。

  • 构造函数初始化列表中基类名、对象名之间的顺序无关紧要,它们各自出现的序可以是任意的,无论它们的顺序怎样安排,基类构造函数的调用和各个成员对象的初性物顺序都是确定的。

  • 具体代码:

    ​
    #include <iostream>
    #include <string.h>
    using namespace std;
    class MM {
    public:   
    	//构造函数
    	//MM() = default;          //使用的函数是默认的构造函数    
         MM(){      cout << "无参构造函数" << endl;    }
         MM(int a){ cout << "具有一个参数的构造函数" << endl; }
    protected:
    };
    
    class Girl {
     public:
     Girl() = delete; //删除默认的构造函数
    protected:
     };
    class Student {
    public:  
      Student() = default; 
      Student(string name, int age){    //做初始化操作       
    	  m_name = name;        m_age = age;  
    	  }  
      void printStudent(){        cout << m_name << "\t" << m_age << endl;    }
     protected:  
      string m_name;  
      int m_age;
     };
     //初始化参数列表
    class Test {
    public:   
    	//构造函数特殊写法  
      Test(int a, int b) :a(a), b(b)  {    } 
       Test():Test(0,0) {}       
    	//无参构造函数调用有参构造函数  
       //构造委托 
       void print(){      cout << a << "\t" << b << endl;    }
    protected:  
    	int a=0; 
    	int b=0;
    };
    struct Data {  
    	int a;  
    	int b;    
    	int c;    
    	Data(int a) :a(a){}Data(int a, int b, int c) :a(a), b(b), c(c){ cout << "调用三个参数的构造函数" << endl; } 
    	void print(){        cout << a << "\t" << b << "\t" << c << endl;    }
    };
    void testData() { Data data = { 1,2,3 }; } //这个过程也是调用构造函数过程,{}中数据个数要和构造函数参数一致
    void printData(Data data){	data.print();
    }
    void printData2(Data& data) { data.print(); }
    
    int main(){
    #if 0
    	 MM mm;
    	 MM girl(1);
    	 //Girl girl;
    	 //普通对象
    	 Student stu("npc", 18);
    	 stu.printStudent();
    	 //new一个对象
    	 Student* pstu = new  Student("执灯", 29);
    	 pstu->printStudent();
    
    	 //对象数组
    	 Student stuArray[3];			//无参构造函数构造
    	 Test test;
    	 test.print();
    
    #endif
    	 Data data(1, 2, 3);
    	 printData(data);
    	 printData2(data);
    	 return 0;
     }
    
    ​

                   

(二) 复制构造函数

拷贝构造函数也叫做复制构造函数。

拷贝构造函数特性

  • 不写拷贝构造函数,存在一个默认拷贝构造函数

  • 拷贝构造函数名和构造函数一样,算是构造函数特殊形态

  • 拷贝构造函数的唯一的一个参数就是对对象引用

    • 普通引用

    • const引用

    • 右值引用--->移动拷贝

  • 当我们通过一个对象产生另一个对象时候就会调用拷贝构造函数

  • 具体代码:

    #include <iostream>
    #include <string>
    using namespace std;
    class MM
    {
    public:
    	MM() {}
    	MM(MM& object)
    	{
    		cout << "调用复制构造函数" << endl;
    	}
    protected:
    
    };
    
    class Girl
    {
    public:
    	Girl(string name, int age) :name(name), age(age) {}
    	Girl() :Girl("", 0) {}
    	Girl(const Girl& object)
    	{
    		//构造函数就是通过一个对象赋值另一个对象
    		name = object.name;
    		age = object.age;
    		cout << "调用拷贝构造函数" << endl;
    	}
    	void print()
    	{
    		cout << name << "\t" << age << endl;
    	}
    protected:
    	string name;
    	int age;
    };
    void printGirl(Girl girl)   //Girl girl=实参
    {
    	girl.print();
    }
    void printMM(Girl& girl)
    {
    	girl.print();
    }
    
    void testGirl()
    {
    	Girl girl("张三", 18);
    	Girl mm(girl);
    	mm.print();
    	Girl beauty = mm;
    	beauty.print();
    	cout << "传入普通变量" << endl;
    	printGirl(girl);
    	cout << "传入引用" << endl;
    	printMM(girl);
    	//匿名对象的拷贝构造函数
    	//匿名对象是右值,右值引用
    	Girl test = Girl("匿名", 18);
    }
    
    class Boy
    {
    public:
    	Boy(string name, int age) :name(name), age(age) {}
    	Boy(Boy&& object)		//右值引用
    	{
    		name = object.name;
    		age = object.age;
    		cout << "右值引用的拷贝构造" << endl;
    	}
    	Boy(Boy& object)
    	{
    		name = object.name;
    		age = object.age;
    		cout << "普通拷贝构造" << endl;
    	}
    protected:
    	string name;
    	int age;
    };
    void testBoy()
    {
    	cout << ".............." << endl;
    	Boy boy("boy", 18);
    	Boy gg = boy;						//调用普通的对象
    	Boy coolman = Boy("sdfd", 28);		//右值引用的拷贝构造函数
    	//没有打印结果,编译器做了优化,看不到
    }
    
    int main()
    {
    	MM mm;
    	MM girl = mm;				//会调用拷贝构造函数
    	MM beauty(girl);			//会调用拷贝构造函数
    	//误区
    	MM  npc;
    	npc = girl;					//运算符重载,不会调用拷贝构造函数
    	testGirl();
    	testBoy();
    	return 0;
    }

(三)析构函数

析构函数特性

  • 声明语法:函数名等于 ~和类名

  • 作用:在该类对象消亡之前进行一些必要的清理工作。

  • 析构函数没有参数,所以析构函数不能被重载也不能缺省

  • 对象死亡(作用域结束、生命周期结束)的最后一个事情是调用析构函数

  • 析构函数都是公有属性的

  • 什么时候写析构函数?

    • 当类的数据成员new了内存就需要自己手动写析构函数

  • 不写析构函数,也会存在一个析构函数,但是不具有释放new的内存功能

  • 具体代码:

    #include <iostream>
    using namespace std;
    class MM
    {
    public:
    	MM()
    	{
    		p = new int;
    	}
    	//手动调用析构函数
    	void freeMemory()
    	{
    		delete p;
    		p = nullptr;
    	}
    	~MM()
    	{
    		cout << "我是析构函数" << endl;
    		delete p;
    		p = nullptr;
    	}
    protected:
    	int* p;
    
    };
    int main()
    {
    	 //版本1:
    	{
    		MM mm;
    		MM* p = new MM;		 	
    		delete p;				//括号作用范围完,立刻马上调用析构函数 
    		p->freeMemory();相当于delete p;
    	}
    		cout << "......" << endl;
    	 //版本2
    		 
    			MM mm;		
    			MM* p = new MM;			
    			delete p;				//立刻马山调用析构函数		 
    	   cout << "......" << endl;
    	return 0;
    }

  • 运行效果: 

  (四)构造函数与析构函数的顺序问题

构造和析构顺序问题

  • 一般情况构造顺序和析构顺序是相反的

  • new对象,调用delete直接被释放

  • static对象,最后释放

具体代码:

#include <iostream>
#include <string>
using namespace std;
class MM {
public:
    MM(string info = "A") :info(info) { cout << info; }
    ~MM() { cout << info; }
protected:
    string info;
};
void testOrder() {
    MM mm1("B");  //构造从上往下 :B, 
    static MM mm2("C");     //构造:C       //最后释放 C   
    MM* p = new MM("D");    //构造:D   
    delete p;               //delete直接调用析构函数:D  D生命周期结束 故打印D,
    MM arr[3];              //构造:AAA             //析构下往上,静态最后一个:AAABC
}
    int main() {
        testOrder();//BCDDAAAAAABC
        return 0;
    }

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/112451.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络协议知识串讲-第38讲-用双十一的故事串起碎片的网络协议(中)

上一节我们讲到,手机App经过了一个复杂的过程,终于拿到了电商网站的SLB的IP地址,是不是该下单了? 别忙,俗话说的好,买东西要货比三家。大部分客户在购物之前要看很多商品图片,比来比去,最后好不容易才下决心,点了下单按钮。下单按钮一按,就要开始建立连接。建立连接…

Spring Cache(边路缓存)

一、Spring Cache介绍 Spring Cache 是Spring - context-xxx.jar中提供的功能&#xff0c;可以结合EHCache&#xff0c;Redis等缓存工具使用。给用户提供非常方便的缓存处理&#xff0c;缓存基本判断等操作,可以直接使用注解实现。 ​ 在包含了Spring - context-xxx.jar的Spri…

07---vue前端实现增删改查

前端VUE通过请求后端实现增删改查&#xff0c;文末会有前端完整代码 1、实现查询功能 一、实现三个条件一起查询 后台需要实现这三个条件的模糊查询 UserController.java //分页查询GetMapping("/page")public IPage<User> findPage(RequestParam Integer p…

【Jenkins】学习笔记

学习笔记一、Jenkins1.1、Jenkins的作用二、下载安装2.1、安装环境2.2、安装GitLab2.3、安装Jenkins三、Jenkins Git Maven 部署配置3.1、安装maven插件3.2、新建项目3.3、自动发布到测试服务器四、publish over ssh 配置4.1、超时机制4.2、shell的日志输出4.3、运行前清理五…

网络地址转换NAT

目录 IP 地址空间即将面临耗尽的危险 NAT 缓解 IP 地址空间耗尽的问题 NAT 的基本方法 VPN 的要点 IP 地址空间即将面临耗尽的危险 互联网采用了无分类编址方式、动态分配IP地址等措施来减缓IP地址空间耗尽的速度 但由于互联网用户数目的激增&#xff0c;特别是大量小型办公…

Linux搭建DHCP服务

DHCP(Dynamic Host Confifuration Protocol,动态主机配置协议)它可以为客户自动分配IP地址、以及缺省网关、DNS服务器的IP地址等TCP/IP参数。 简单说,就是在DHCP服务器上有一个存放着IP地址、网关、DNS等参数。当客户端请求使用时,服务器则负责将相应的参数分配给客户端,…

win10环境下基于face_recognition搭建自己的人脸识别软件

在win10环境下安装face_recognition&#xff0c;了解face_recognition中api的使用&#xff0c;如人脸截取、人脸矫正、人脸特征提取、人脸关键点提取、人脸mask获取、人脸特征比对等功能。最后构建自己的人脸数据库&#xff0c;使用knn实现人脸识别软件。 1、安装face_recogni…

【圣诞特辑】码一个漂漂亮亮的圣诞树(Single Dog版)

目录 前言 一、C语言版圣诞树 1.代码实现 2.效果图 二、python版圣诞树 1.代码实现 2.效果图​ 三、html5版圣诞树 1.代码实现 2.效果图 总结 前言 圣诞节即将来临&#xff0c;圣诞树也是必不可少的装饰之一。圣诞树是一棵绿叶繁茂的树&#xff0c;上面挂满了彩色的灯…

Nginx学习笔记2【尚硅谷】

host文件修改时&#xff0c;可以更改用户组权限或者复制到某个有权限的位置修改完再复制替换之前的文件。 在server{}中&#xff0c;listenserver_name两个加一起是唯一的。 代理服务器就是一个网关。 配置Nginx反向代理&#xff1a; 注意&#xff1a;在写proxy_pass时&#xf…

java+selenium环境搭建

目录 1.写在前面的话: 2.下载谷歌驱动 3.添加Selenium依赖(我这里添加的是4.0.0版本的) 4.在操作过程中可能出现的问题&解决办法 目录 1.写在前面的话: 2.下载谷歌驱动 3.添加Selenium依赖(我这里添加的是4.0.0版本的) 1.写在前面的话: (1)java版本最低要求为8,Chro…

SpringBoot整合Activemq

目录 一、Pom.xml 二、Spring配置文件 三、队列 四、主题 一、Pom.xml <dependencies><!-- activemq核心依赖包 --><dependency><groupId>org.apache.activemq</groupId><artifactId>activemq-all</artifactId><version>…

终生学习——读书有什么坏处

一般爱读书者往往受到赞扬&#xff0c;但仍然需要谨记一些读书的原则 目录 一、读书的整体观点 二、为什么需要知道读书的坏处 三、何时会出现读书的坏处 四、读书有什么坏处 1、100%全部相信书中的观点&#xff0c;进而实践了错误观点 2、不实践 五、如何杜绝读书的害处…

程序员为了少加班想了这几招

&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3; &#x1f38d;大家好&#xff0c;我是慕枫 &#x1f38d;前阿里巴巴高级工程师&#xff0c;InfoQ签约作者、阿里云专家博主&#xff0c;一直致力于用大白话讲解技术知识 &#x…

一个简单的Linux内核字符驱动程序编写

一、背景 为了了解设备驱动程序的框架&#xff0c;在此编写一个简单的字符驱动程序&#xff0c;以此来对驱动程序的框架进行一个简单的了解。 二、设备驱动程序 所谓设备驱动程序&#xff0c;其实就是计算机硬件与外部设备进行通信的接口。由于硬件设备各式各样&#xff0c;…

【Ctfer训练计划】——(四)

作者名&#xff1a;Demo不是emo 主页面链接&#xff1a;主页传送门创作初心&#xff1a;舞台再大&#xff0c;你不上台&#xff0c;永远是观众&#xff0c;没人会关心你努不努力&#xff0c;摔的痛不痛&#xff0c;他们只会看你最后站在什么位置&#xff0c;然后羡慕或鄙夷座右…

【kafka】学习笔记(三)

学习笔记七、Kafka-Eagle 监控7.1 环境准备7.2 Eagle 安装7.3、修改配置文件7.4、添加环境变量7.5、启动Eagle八、Kafka-Kraft 模式8.1、Kafka-Kraft 集群部署8.2、初始化集群数据目录8.3、启动 kafka 集群8.4、测试8.5、集群启动脚本九、SpringBoot集成Kafka七、Kafka-Eagle 监…

RabbitMQ 第一天 基础 4 RabbitMQ 的工作模式 4.3 Routing 路由模式

RabbitMQ 【黑马程序员RabbitMQ全套教程&#xff0c;rabbitmq消息中间件到实战】 文章目录RabbitMQ第一天 基础4 RabbitMQ 的工作模式4.3 Routing 路由模式4.3.1 模式说明4.3.2 代码编写4.3.3 小结第一天 基础 4 RabbitMQ 的工作模式 4.3 Routing 路由模式 4.3.1 模式说明 …

React 学习笔记总结(四)

文章目录1. 创建组件流程(以及脚手架环境流程)2. 样式 的模块化3. 常用快捷生成4. 通用性 组件编码流程5. React脚手架 配置代理5.1 React 引入 ajax库5.2 第一种配置代理方式(package.json)5.3 第二种代理方式(setupProxy.js)6. React List列表效果实现7. React 消息订阅与发布…

“内卷之王”vivo:成败即将见分晓

文丨熔财经 作者|XL 12月22日&#xff0c;随着年底收官之作S16系列正式发布&#xff0c;vivo完成了自己的年度答卷。2022年&#xff0c;vivo总体风头正盛&#xff0c;尤其在第三季度一马当先稳居国内出货量榜首&#xff0c;市占比提升到20.0%&#xff0c;领先第二名3%。这是一…

elementUI中el-table每行异常高度原因排查,累死

理论上不单独设置高度的话&#xff0c;表格每一个应该是默认的高度才对&#xff0c;我说的没错吧&#xff0c; 但是请看实际情况&#xff1a; 这是默认情况下的高度为48 还有两外一个表格&#xff0c;我也没有设置高度&#xff0c;但是但是&#xff1a;这个高度竟然达到了71&…