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

c++ 构造函数与析构函数

本文参考菜鸟教程,仅作笔记用。

构造函数

构造函数(Constructor)是一种特殊的方法,用于在创建对象时进行初始化操作。构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。在面向对象编程中,通常每个类都可以有一个构造函数。构造函数的作用是初始化对象的状态,为对象的属性赋予初始值,以确保对象在创建后处于一个合适的状态。

在继承关系中,子类可以继承父类的属性和方法,但是构造函数却不能直接继承。这是因为构造函数的特殊性质,它在对象创建时被调用,用于初始化该对象的状态。当子类继承父类时,子类可以使用父类的属性和方法,但是子类的构造函数需要负责初始化子类自己的属性,而不能直接继承父类的构造函数。

通常情况下,如果子类没有定义自己的构造函数,那么会隐式地调用父类的构造函数来初始化子类的实例但是如果子类定义了自己的构造函数,那么子类的构造函数就会覆盖父类的构造函数,这样父类的构造函数就无法被子类直接继承和使用了。

#include <iostream>using namespace std;class Line
{public:void setLength( double len );double getLength( void );Line();  // 这是构造函数private:double length;
};// 成员函数定义,包括构造函数
Line::Line(void)
{cout << "Object is being created" << endl;
}void Line::setLength( double len )
{length = len;
}double Line::getLength( void )
{return length;
}
// 程序的主函数
int main( )
{Line line;// 设置长度line.setLength(6.0); cout << "Length of line : " << line.getLength() <<endl;return 0;
}
<<  Object is being created
<<  Length of line : 6

带参数的构造函数

#include <iostream>using namespace std;class Line
{public:void setLength( double len );double getLength( void );Line(double len);  // 这是构造函数private:double length;
};// 成员函数定义,包括构造函数
Line::Line( double len)
{cout << "Object is being created, length = " << len << endl;length = len;
}void Line::setLength( double len )
{length = len;
}double Line::getLength( void )
{return length;
}
// 程序的主函数
int main( )
{Line line(10.0);// 获取默认设置的长度cout << "Length of line : " << line.getLength() <<endl;// 再次设置长度line.setLength(6.0); cout << "Length of line : " << line.getLength() <<endl;return 0;
}
<< Object is being created, length = 10
<< Length of line : 10
<< Length of line : 6

使用初始化列表来初始化字段

初始化列表允许我们在构造函数中以更加直接和高效的方式初始化类的成员变量,特别是对于常量或者引用类型的成员变量尤其有用。
使用初始化列表来初始化字段:

Line::Line( double len): length(len)
{cout << "Object is being created, length = " << len << endl;
}

上面的语法等同于如下语法:

Line::Line( double len)
{length = len;cout << "Object is being created, length = " << len << endl;
}

再举个例子

#include <iostream>
#include <string>class Car {
private:std::string& owner;  // Reference member variablestd::string model;public:// Constructor with initialization listCar(std::string& o, const std::string& m) : owner(o), model(m) {// Constructor body (if needed)}void displayInfo() const {std::cout << "Owner: " << owner << ", Model: " << model << std::endl;}
};int main() {std::string alice = "Alice";std::string bob = "Bob";// Initializing objects of class Car using initialization listCar car1(alice, "Toyota");car1.displayInfo();Car car2(bob, "Honda");car2.displayInfo();return 0;
}
<< Owner: Alice, Model: Toyota
<< Owner: Bob, Model: Honda

析构函数

类的析构函数是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行。

析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数。析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。

子类会继承父类的析构函数,但并不是通过继承其实现。当子类的对象销毁时,会先调用子类的析构函数,然后再调用父类的析构函数。这种顺序确保了对象的析构顺序与构造顺序相反。
如果父类有虚析构函数(通过在析构函数前面加上 virtual关键字),那么子类也会继承这个虚析构函数。这是为了实现多态性,确保在使用基类指针指向派生类对象时正确地释放资源。

加上 virtual 关键字确实是声明虚函数的方式,但在析构函数前面加上 virtual关键字有特定的作用。这种做法是为了确保正确的析构函数调用顺序和资源释放。

当你有一个基类指针指向派生类对象时,如果基类的析构函数是虚函数(即声明为virtual),那么在销毁这个对象时,会根据实际对象的类型(基类或派生类)来调用适当的析构函数。这种机制称为动态绑定或者多态性。

具体来说,如果基类的析构函数不声明为虚函数,那么当你通过基类指针删除一个派生类对象时,只会调用基类的析构函数,而不会调用派生类的析构函数。这可能导致派生类对象中的资源(如动态分配的内存)没有被正确释放,从而产生内存泄漏或其他问题。

因此,为了确保在继承体系中正确地释放资源,通常建议在基类的析构函数前面加上 virtual关键字,以启用动态绑定机制。这样,无论通过基类指针如何删除对象,都能正确调用对象的实际类型的析构函数,确保资源的正确释放。

总结一下,加上 virtual 关键字在析构函数中的作用是确保在继承体系中正确地调用对象的析构函数,从而实现多态性和正确的资源管理。

#include <iostream>using namespace std;class Line
{public:void setLength( double len );double getLength( void );Line();   // 这是构造函数声明~Line();  // 这是析构函数声明private:double length;
};// 成员函数定义,包括构造函数
Line::Line(void)
{cout << "Object is being created" << endl;
}
Line::~Line(void)
{cout << "Object is being deleted" << endl;
}void Line::setLength( double len )
{length = len;
}double Line::getLength( void )
{return length;
}
// 程序的主函数
int main( )
{Line line;// 设置长度line.setLength(6.0); cout << "Length of line : " << line.getLength() <<endl;return 0;
}
<< Object is being created
<< Length of line : 6
<< Object is being deleted

注意

初始化顺序最好要按照变量在类声明的顺序一致,否则会出现下面的特殊情况:

#include<iostream>using namespace std;class Student1 {public:int a;int b;void fprint(){cout<<" a = "<<a<<" "<<"b = "<<b<<endl;}Student1(int i):b(i),a(b){ }    //异常顺序:发现a的值为0  b的值为2  说明初始化仅仅对b有效果,对a没有起到初始化作用 
//         Student1(int i):a(i),b(a){ } //正常顺序:发现a = b = 2 说明两个变量都是初始化了的  Student1()                         // 无参构造函数{ cout << "默认构造函数Student1" << endl ;}Student1(const Student1& t1) // 拷贝构造函数{cout << "拷贝构造函数Student1" << endl ;this->a = t1.a ;}Student1& operator = (const Student1& t1) // 赋值运算符{cout << "赋值函数Student1" << endl ;this->a = t1.a ;return *this;}};
class Student2
{public:Student1 test ;Student2(Student1 &t1){test  = t1 ;}
//     Student2(Student1 &t1):test(t1){}
};
int main()
{Student1 A(2);        //进入默认构造函数 Student2 B(A);        //进入拷贝构造函数 A.fprint();            //输出前面初始化的结果 
}

在这里插入图片描述
一个类内可以有多个构造函数,可以是一般类型的,也可以是带参数的,相当于重载构造函数,但是析构函数只能有一个

class Matrix
{
public:Matrix(int row, int col);                                            //普通构造函数Matrix(const Matrix& matrix);                                        //拷贝构造函数Matrix();                                                            //构造空矩阵的构造函数void print(void);~Matrix();
};

总结上述两点注意事项,代码如下:

#include<iostream>using namespace std;class Student1 {
public:int a=0;int b=0;void fprint() {cout << " a = " << a << " " << "b = " << b << "\n"<<endl;}Student1(){cout << "无参构造函数Student1" << endl;}Student1(int i):a(i),b(a){ cout << "有参参构造函数Student1" << endl;} Student1(const Student1& t1){cout << "拷贝构造函数Student1" << endl;this->a = t1.a;this->b = t1.b;}Student1& operator = (const Student1& t1) // 重载赋值运算符{cout << "赋值函数Student1" << endl;this->a = t1.a;this->b = t1.b;return *this;}};
class Student2
{
public:Student1 test;Student2(Student1& t1) {t1.fprint();cout << "D: ";test = t1;}//     Student2(Student1 &t1):test(t1){}
};
int main()
{cout << "A: ";Student1 A;A.fprint();cout << "B: ";Student1 B(2); B.fprint();cout << "C: ";Student1 C(B); C.fprint(); cout << "D: ";Student2 D(C);D.test.fprint();
}/*A: 无参构造函数Student1a = 0 b = 0B: 有参参构造函数Student1a = 2 b = 2C:拷贝构造函数Student1a = 2 b = 2D: 无参构造函数Student1a = 2 b = 2D: 赋值函数Student1a = 2 b = 2

相关文章:

c++ 构造函数与析构函数

本文参考菜鸟教程&#xff0c;仅作笔记用。 构造函数 构造函数&#xff08;Constructor&#xff09;是一种特殊的方法&#xff0c;用于在创建对象时进行初始化操作。构造函数的名称与类的名称是完全相同的&#xff0c;并且不会返回任何类型&#xff0c;也不会返回 void。在面…...

Lc63---1859将句子排序(排序)---Java版(未写完)

1.题目描述 2.思路 &#xff08;1&#xff09;首先将句子按空格分割成若干单词。 &#xff08;2&#xff09;每个单词的最后一个字符是它的位置索引。我们可以通过这个索引将单词恢复到正确的位置。 &#xff08;3&#xff09;按照单词的索引顺序排序这些单词。 &#xff08;4…...

centos7-8/redhat7-8一键安装配置vsftp服务

1.脚本介绍 1.1.介绍&#xff1a; linux下一键安装及配置vsftpd服务 &#xff0c;通过执行install.sh脚本&#xff0c;脚本会根据参数区域的值执行安装和配置vsftp服务&#xff0c;安装后会创建一个默认ftp用户wangxf密码wangxf2023 1、支持自定义安装(更改脚本内参数值) 2、…...

7月24日JavaSE学习笔记

序列化版本控制 序列化&#xff1a;将内存对象转换成序列&#xff08;流&#xff09;的过程 反序列化&#xff1a;将对象序列读入程序&#xff0c;转换成对象的方式&#xff1b;反序列化的对象是一个新的对象。 serialVersionUID 是一个类的序列化版本号 private static fin…...

微信小程序教程008:事件绑定

文章目录 事件绑定1、什么是事件2、小程序中常用事件3、事件对象的属性列表4、target和currentTarget的区别5、bindtap的语法格式6、在事件处理函数中为data中的数据赋值7、事件传参数8、bind:input语法格式9、实现文本框和data之间的数据同步事件绑定 1、什么是事件 事件是渲…...

企业级-实现Nginx的静态文件服务器映射

作者&#xff1a;fyupeng 技术专栏&#xff1a;☞ https://github.com/fyupeng 项目地址&#xff1a;☞ https://github.com/fyupeng/distributed-blog-system-api 留给读者 开发人员往往会经常需要通过浏览器下载文件、图片或者PDF或者缩略图等&#xff0c;这时候我们可以根据…...

CTF Web SQL注入 10000字详解

这里写目录标题 涉及的数据库知识unionorder bydatabase()information_schemalimit--空格注释replaceinto outfilelikeGROUP BYHAVINGGROUP BY、HAVING、WHERE之间的关系regexp 原理信息收集操作系统数据库判断注入点注入点类型POST注入数字型注入字符型注入搜索型注入Insert/u…...

动态SLAM:如何判断一个特征是动态特征(对极几何)

文章目录 1.什么是极线、极点和极面2.如何判断其为动态点特征3.如何判断其为动态线特征 1.什么是极线、极点和极面 由图可知&#xff0c;C1,C2,X(X1,X2)组成了一个三角平面&#xff0c;这个三角所在的平面就是极面 在这个极平面中&#xff0c;和成像平面相交的线是极线&#xf…...

【C++】初识C++基础篇·一(命名空间,函数重载,缺省参数,引用);

文章目录 前言1.输入与输出输出输入cin和scanf的对比 2.命名空间2.1namespace存在的意义2.2namespace的使用3.缺省参数4.函数重载重载函数的调用规则 5.引用 前言 我们先通过一段简单的代码来拉开C的序幕&#xff1b; //text.cpp #include<iostream> #include<stdio…...

2024年道路运输安全员考试题库及答案

一、判断题 1.国家制订《中华人民共和国道路交通安全法》的目的是为了维护道路交通秩序&#xff0c;预防和减少交通事故&#xff0c;保护人身安全&#xff0c;保护公民、法人和其他组织的财产安全及其他合法权益&#xff0c;提高通行效率。 答案&#xff1a;正确 2.依据《中…...

Linux Vim教程(十二):语法高亮与代码折叠

目录 1. 语法高亮 1.1 启用语法高亮 1.2 设置配色方案 1.3 自定义语法高亮 2. 代码折叠 2.1 启用代码折叠 2.2 设置折叠方法 2.3 手动折叠 2.4 基于缩进的折叠 2.5 基于语法的折叠 3. 案例 3.1 配置文件 3.2 编辑Python文件 3.3 使用折叠功能 4. 高级使用技巧 …...

JavaScript(18)——事件类型,事件对象

事件类型 鼠标事件&#xff1a; click&#xff1a;鼠标点击 mouseenter&#xff1a;鼠标经过 mouseleave&#xff1a;鼠标离开 焦点事件&#xff1a; focus&#xff1a;获得焦点 blur&#xff1a;失去焦点 键盘事件&#xff1a; Keydown&#xff1a;键盘按下触发 Keyup&#…...

有效组织离散变量:指针数组在C语言中的应用

把离散变量组织起来&#xff0c;访问起来更加方便&#xff0c;无需一个个变量单独赋值。 如modbus读写reg&#xff0c; 把a\b\c\d实时变化分散的变量组织成一个数组reg&#xff0c;方便获取 相当于变量的内存地址池 int main() {int a 10, b 20, c 30, d 40;int i;int *re…...

qt 应用正在运行时,如何更新升级exe文件

在Qt应用正在运行时&#xff0c;直接替换同名的.exe文件可能会导致文件正在使用中的错误。为了安全地更新.exe文件&#xff0c;你可以采取以下步骤&#xff1a; 创建一个临时的.exe文件。 等待当前.exe文件的进程关闭。 删除原有的.exe文件。 将临时.exe文件重命名为原有的.…...

git的rebase 和 merge 的区别

rebase 和 merge 的区别 Merge&#xff08;合并&#xff09;和 Rebase&#xff08;变基&#xff09;是 Git 中两种常用的分支整合方式&#xff0c;它们有不同的工作原理和适用场景&#xff1a; Merge&#xff08;合并&#xff09;&#xff1a; ● Merge 操作将两个分支的不同提…...

django基于大数据的电影推荐系统-计算机毕业设计源码71246

目 录 摘 要 1 绪论 1.1 选题背景与意义 1.2研究现状 1.3研究内容 1.4 开发环境 1.5论文结构与章节安排 2 相关理论和技术 2.1 协同过滤算法 2.2 B/S体系结构介绍 2.3 Python爬虫技术 2.4 Django框架介绍 2.5 MySQL数据库 3 电影推荐系统系统分析 3.1 可行性分析…...

reverse_re3-入土为安的第十天

一个迷宫题 shirtf12发现flag字样 点进去发现迷宫 675 应该是3 * 15*15 即有三个迷宫 shifte提取 import numpy as np# 你的数据&#xff08;长度应为 225 的倍数&#xff09; dword_202020 [1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,3,1,1,0,0,0,0,0,0,1,1,1,1,1,0,0,…...

fastapi之一

文章目录 安装运行HTTP 请求方法示例 POSTMAN 检验GETPOSTPUTDELETE HTTP 状态码示例GETPOST 综合示例POSTGETPUTDELETE 总结 安装 pip install fastapi或者 pip install fastapi -i https://mirrors.aliyun.com/pypi/simple上面两种方法均可以&#xff0c;选择一个即可&…...

【C语言报错已解决】Format String Vulnerability

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引言 在日常开发中&#xff0c;我们经常会遇到各种各样的bug&#xff0c;其中格式化字符串漏洞报错可能是最让人头疼的一种。这…...

关于一个简单的顺序表代码

1.首先是头文件SeqList.h的代码&#xff1a; #pragma once #include<stdio.h> #include<assert.h> #include<stdlib.h> typedef int SXBint; typedef struct SL {SXBint* a;int size;int capacity; }SLnode; //初始化 void SeqLsitInit(SLnode* ps); //尾插…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

基于Flask实现的医疗保险欺诈识别监测模型

基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施&#xff0c;由雇主和个人按一定比例缴纳保险费&#xff0c;建立社会医疗保险基金&#xff0c;支付雇员医疗费用的一种医疗保险制度&#xff0c; 它是促进社会文明和进步的…...

【项目实战】通过多模态+LangGraph实现PPT生成助手

PPT自动生成系统 基于LangGraph的PPT自动生成系统&#xff0c;可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析&#xff1a;自动解析Markdown文档结构PPT模板分析&#xff1a;分析PPT模板的布局和风格智能布局决策&#xff1a;匹配内容与合适的PPT布局自动…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...

Java毕业设计:WML信息查询与后端信息发布系统开发

JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发&#xff0c;实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构&#xff0c;服务器端使用Java Servlet处理请求&#xff0c;数据库采用MySQL存储信息&#xff0…...

宇树科技,改名了!

提到国内具身智能和机器人领域的代表企业&#xff0c;那宇树科技&#xff08;Unitree&#xff09;必须名列其榜。 最近&#xff0c;宇树科技的一项新变动消息在业界引发了不少关注和讨论&#xff0c;即&#xff1a; 宇树向其合作伙伴发布了一封公司名称变更函称&#xff0c;因…...

在树莓派上添加音频输入设备的几种方法

在树莓派上添加音频输入设备可以通过以下步骤完成&#xff0c;具体方法取决于设备类型&#xff08;如USB麦克风、3.5mm接口麦克风或HDMI音频输入&#xff09;。以下是详细指南&#xff1a; 1. 连接音频输入设备 USB麦克风/声卡&#xff1a;直接插入树莓派的USB接口。3.5mm麦克…...

API网关Kong的鉴权与限流:高并发场景下的核心实践

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 引言 在微服务架构中&#xff0c;API网关承担着流量调度、安全防护和协议转换的核心职责。作为云原生时代的代表性网关&#xff0c;Kong凭借其插件化架构…...

Python网页自动化Selenium中文文档

1. 安装 1.1. 安装 Selenium Python bindings 提供了一个简单的API&#xff0c;让你使用Selenium WebDriver来编写功能/校验测试。 通过Selenium Python的API&#xff0c;你可以非常直观的使用Selenium WebDriver的所有功能。 Selenium Python bindings 使用非常简洁方便的A…...

QT开发技术【ffmpeg + QAudioOutput】音乐播放器

一、 介绍 使用ffmpeg 4.2.2 在数字化浪潮席卷全球的当下&#xff0c;音视频内容犹如璀璨繁星&#xff0c;点亮了人们的生活与工作。从短视频平台上令人捧腹的搞笑视频&#xff0c;到在线课堂中知识渊博的专家授课&#xff0c;再到影视平台上扣人心弦的高清大片&#xff0c;音…...