当前位置: 首页 > news >正文

C++ 构造函数与析构函数

构造器和析构器的作用

1.C++构造函数和析构函数主要负责构建对象销毁对象,在构建对象的时候系统自己调用类中的构造函数, 在对象作用域结束后,调用析构函数销毁对象

2.构造函数用来完成事先的初始化和准备工作 (申请分配内存)析构函数 用来完成事后所必须的清理工作 (清理内存)

3.构造器和析构器是程序员自己写出的 创建或销毁一个对象所自动调用的方法


构造器(constructed)

系统在创建某个类的实例时会第一时间自动调用这个类的构造器

定义构造器的前提(面对对象编程技术开发程序的基本步骤)

定义一个有属性和方法的类(模板)
为该类创建一个成员变量(实现)

构造器是类中一种特殊的方法(成员函数)


构造器和通常方法的主要区别

构造器的名字必须和它所在的类的名字一样
系统在创建某个类的实例时会第一时间自动调用这个类的构造器
构造器永远不会返回任何值
创建构造函数时,需要把构造函数声明放进类里面,结束类中声明后,则需要开始定义构造函数本身

声明一个构造器

class Car //构建一个类
{
	Car(void);//声明Car类的构建函数
}

注意大小写与类名保持一致,在结束声明之后开始定义构造器本身:

Car::Car()//由于构造函数不返回任何值 也不带任何参数 因此此函数不必写成void Car::Car(void) 格式为 ClassName::ClassName()
{
	color = "WHITE";
	engine = "V8";
	wheel = 4;
	gas_tank = FULL_GAS;
 }

注意:
每个类中必须和至少有一个构造器函数如果你未在类中定义构造器函数 那么编译器会使用如下语法帮你定义一个构造器Classname::ClassName(){}这是一个没有代码内容的空构造器,除此之外,编译器还会替你创建一个副本构造器CopyConstructor且此构造器的状态为不可见


构造对象数组:

之前说过,数组可以是任何一种数据类型,这当然也包括对象

如:Car mycars[10],其调用方法依旧是:mycar[x].running其中x表示指定对象数组元素的下标


来自 操作符重载项目 ↓

以在构造器形参列表后方加上:号的方式进行类成员的初始化

现在有一个类为Comlex类 此类的构造器有两个传入参数[r,i],此类有两个double类成员[real,imag]
Comlex类构造器

Comlex(double r=0, double i=0) :real(r), imag(i) {};

为什么在构造器形参列表后面加上冒号:
其实冒号后的内容:real(r), imag(i)是初始化值,意为传入的形参数据用来初始化类成员,相当于:

Comlex(double r=0, double i=0) //构造器形参列表
{
		real = r;
		imag=i;
}

注意:
此时Comlex类的构造器参数列表有两个参数,也就是说在建立对象时,需要在对象名后方跟上参数列表并输入两个参数,例如:

int main()
{Comlex a(3.0,5.0);}

当主函数中建立Comlex对象实例时,未给该对象添加参数列表时,例如:

int main(){Comlex a;}

则需要保证类的构造器在声明时构造器的形参列表中的形参一定是被初始化的(有默认值)

Comlex(double r=0, double i=0) 

来自 操作符重载项目 ↑


析构器(finalizer)

析构器:对象消亡时,自动被调用,用来释放对象占用的空间

从前面的内容我们了解到,在创建对象时,系统都会自动调用一个特殊的方法,即构造器
相应地,在销毁一个对象时,系统也应该会调用另一个特殊方法达到效果。没错,这就是 析构器

构造器和析构器二者相辅相成,有许多共同之处。首先,析构器有着和构造器/类一样的名字,只不过名字前面多了一个波浪符~的前缀

声明一个析构器

class Car
{
	~Car();
}

其次,析构器也永远不带任何返回值
另外,析构器是不带任何参数的,所以析构器的声明永远是如下格式:

~ClassName()

注意:
1.一个类最多只有一个析构函数
2.不显式的定义析构函数系统会调用默认析构函数
3.栈中内存由系统自由分配和释放,使用new创建的指针对象是在堆中分配内存 当不需要该对象时 我们需要手动去释放内存,否则会导致内存泄漏


案例 使用类 构造函数 析构函数 编写一个打印名人名言的程序

#include <iostream>
#include<windows.h>
#include <fstream>
#include <string> //如果需要使用getline函数则必须包含此头文件

using namespace std;


class Quote //类名的第一个字母习惯上最好采用大写 
{

public:
	//建立一个类 :存放汽车数据 车漆色 引擎类型 油量 和 几个轮子

	string quote,speaker;
	ofstream  fileOutPut;

	Quote(void);
	//todo在类中声明构造器
	//构造器的命名必须和其所在的类的类名一致
	//构造器不返回任何值 所以不用写void 析构器也不带任何参数

	~Quote();
	//todo在类中声明析构器
	//析构器有着和构造器或类一样的名字,比构造器多个波浪符 " ~ " 前缀
	//析构器不返回任何值 所以不用写void 析构器也不带任何参数 所以析构器声明永远是如下格式 ~ClassName();

	void inputQuote();
	//todo定义类中的普通成员函数(类中 声明 部分)
	//声明一个写入名言的方法

	void inputSpeaker();
	//声明一个写入名人的方法

	bool write();
	//声明一个将输入的名人名言写入到指定文件的方法

};


Quote::Quote()
{
	fileOutPut.open("Quote.txt", ios::app);
}
//todo在类外部对类中声明的构造器进行定义
//每个类至少要有一个构造器 如果在类中没有定义构造器 编译器会使用如下语法自动帮你定义一个构造器 ( Classname::ClassName(){} )除此之外 编译器还会替你创建一个副本构造器CopyConstructor

Quote::~Quote()
{
	fileOutPut.close();
}
//todo对类中声明的析构器器进行定义

void Quote::inputQuote()
{
	getline(cin,quote);
}

void Quote::inputSpeaker()
{
	getline(cin, speaker);
}

bool Quote::write()
{
	if (fileOutPut.is_open())
	{
		fileOutPut << quote << "|" << speaker << "\n";
	}
	else
	{
		return false;
	}
}


//todo案例 名人名言写入程序
int main()
{
	Quote writequote;
	cout << "请输入一句名言:" << endl;
	writequote.inputQuote();

	cout << "请输入名言的作者:" << endl;
	writequote.inputSpeaker();

	if (writequote.write())//当write这个函数bool值为true时此条件成立 
	{
		cout << "已成功写入文件 请打开查看" << endl;
	}
	else
	{
		cout <<"文件写入失败 请检查 " <<endl;
	}

	return 0;
}

效果
在这里插入图片描述
在这里插入图片描述
注:ios::app在未检测到相关用户文件的情况下,会自动在源文件夹中建立一个同名文件

相关文章:

  • MFC应用程序中处理消息的顺序,创建窗口的过程关闭窗口的顺序(非模态窗口),打开模式对话框的函数调用顺序...
  • C++ this指针 与 类的继承
  • OpenGL_Qt学习笔记之_07(闪烁的星星)
  • C++ 继承机制中的构造器与析构器
  • C#数组
  • C++ 访问控制
  • ASA842配置内网DNS欺骗测试
  • C++ 覆盖方法与重载方法
  • Ubuntu 12.04 ping 响应慢
  • C++ 静态属性和静态方法
  • C++ this指针与静态属性的关系
  • .NET I/O 学习笔记:对文件和目录进行解压缩操作
  • C++ new和delete动态分配和释放内存
  • C++ 类对象与类指针(静态和动态多态)
  • 第六天 if if…else 三木运算符
  • ES6指北【2】—— 箭头函数
  • 分享的文章《人生如棋》
  • 【翻译】Mashape是如何管理15000个API和微服务的(三)
  • 【技术性】Search知识
  • fetch 从初识到应用
  • IndexedDB
  • javascript 哈希表
  • JavaSE小实践1:Java爬取斗图网站的所有表情包
  • JS+CSS实现数字滚动
  • opencv python Meanshift 和 Camshift
  • PHP 的 SAPI 是个什么东西
  • spring boot 整合mybatis 无法输出sql的问题
  • webpack4 一点通
  • 使用阿里云发布分布式网站,开发时候应该注意什么?
  • 适配iPhoneX、iPhoneXs、iPhoneXs Max、iPhoneXr 屏幕尺寸及安全区域
  • 携程小程序初体验
  • # include “ “ 和 # include < >两者的区别
  • #常见电池型号介绍 常见电池尺寸是多少【详解】
  • (附源码)apringboot计算机专业大学生就业指南 毕业设计061355
  • (附源码)springboot宠物管理系统 毕业设计 121654
  • (更新)A股上市公司华证ESG评级得分稳健性校验ESG得分年均值中位数(2009-2023年.12)
  • (三)Hyperledger Fabric 1.1安装部署-chaincode测试
  • (深度全面解析)ChatGPT的重大更新给创业者带来了哪些红利机会
  • (十三)Maven插件解析运行机制
  • (转)scrum常见工具列表
  • ./和../以及/和~之间的区别
  • .net core webapi 部署iis_一键部署VS插件:让.NET开发者更幸福
  • .NET Core/Framework 创建委托以大幅度提高反射调用的性能
  • .net 流——流的类型体系简单介绍
  • /dev/sda2 is mounted; will not make a filesystem here!
  • /dev下添加设备节点的方法步骤(通过device_create)
  • @select 怎么写存储过程_你知道select语句和update语句分别是怎么执行的吗?
  • [ vulhub漏洞复现篇 ] Apache APISIX 默认密钥漏洞 CVE-2020-13945
  • [28期] lamp兄弟连28期学员手册,请大家务必看一下
  • [AR]Vumark(下一代条形码)
  • [BUUCTF 2018]Online Tool(特详解)
  • [CISCN2019 华东南赛区]Web4
  • [CQOI 2011]动态逆序对
  • [Erlang 0129] Erlang 杂记 VI 2014年10月28日
  • [idea]关于idea开发乱码的配置