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

从0开始C++(三):构造函数与析构函数详解

目录

构造函数 

构造函数的基本使用

构造函数也支持函数重载

构造函数也支持函数参数默认值

构造初始化列表

拷贝构造函数

浅拷贝和深拷贝

析构函数

 总结

练习一下ヽ( ̄▽ ̄)ノ 


构造函数 

构造函数的基本使用

构造函数是一种特殊的成员函数,用于创建对象时初始化,写法上有以下要求:

● 函数名称必须与类名完全一样。

● 构造函数不写返回值

● 如果程序员不手动编写构造函数,编译器就会自动添加一个默认无参数的构造函数。

● 手动添加构造函数后,编译器就不会自动添加默认无参构造函数。

class Car
{
private://权限:最私有的权限string brand;   // 品牌string modle;   // 型号int weight;     // 重量
public: // 权限:最开放的权限Car(string b,string m,int w) //手动添加的构造函数{brand=b;modle=m;weight=w;}string get_brand()   //外部函数接口{return brand;}string get_modle(){return modle;}int get_weight(){return weight;} 
};
int main()
{Car *myCar = new Car; //  创建堆内存对象//cout << Car.brand << endl;  //错误,brand是私有成员 不能外部访问cont << Car.get_brand << endl; //可以使用预留的接口访问 
}

构造函数也支持函数重载

class Car
{
private://权限:最私有的权限string brand;   // 品牌string modle;   // 型号int weight;     // 重量
public: // 权限:最开放的权限Car(string b,string m,int w) // 有参构造函数{brand=b;modle=m;weight=w;}Car()    // 无参构造函数{brand="xiaomi";modle="su7";weight=1500;}string get_brand()   // 外部函数接口{return brand;}string get_modle(){return modle;}int get_weight(){return weight;} 
};
int main()
{Car *myCar = new Car; //  调用无参构造函数Car *myCar2 = new Car("HuaWei","问界","2000"); // 此时调用有参构造函数}

构造函数也支持函数参数默认值

从第一个设置默认值的变量开始,在其变量之后的所有参数都要加默认值,在他之前的变量可以不加默认值。

class Car
{
private://权限:最私有的权限string brand;   // 品牌string modle;   // 型号int weight;     // 重量
public: // 权限:最开放的权限Car(string b="xiaomi",string m="su7",int w=1500) // 全缺省时,不能和无参构造函数同时存在{brand=b;modle=m;weight=w;}//    Car()    // 无参构造函数//    {//        brand="xiaomi";//        modle="su7";//       weight=1500;//    }string get_brand()   // 外部函数接口{return brand;}string get_modle(){return modle;}int get_weight(){return weight;} 
};
int main()
{Car *myCar = new Car; //  全缺省Car *myCar2 = new Car("问界","M7","2000"); // 此时调用有参构造函数}

构造初始化列表

当构造函数的局部变量与成员变量重名时可以使用构造初始列表的方式区分,此外,使用构造初始化列表还可以给被 const 修饰的成员变量赋值。

class Car
{
private://权限:最私有的权限const string brand;   // 品牌string modle;   // 型号int weight;     // 重量
public: // 权限:最开放的权限Car(string b,string modle,int w):brand(b),modle(modle),weight(w){} // 用构造初始化列表的方式赋值string get_brand()   // 外部函数接口{return brand;}string get_modle(){return modle;}int get_weight(){return weight;} 
};
int main()
{Car *myCar = new Car("问界","M7","2000"); // 此时调用有参构造函数}

拷贝构造函数

C++的拷贝构造函数是一种特殊的成员函数,用于创建一个对象的副本。它的参数是一个对象的引用,通过这个参数可以将一个对象的值复制给另一个对象。

拷贝构造函数通常在以下情况下被调用:

1、当用一个对象初始化另一个对象时,会调用拷贝构造函数。例如:

class MyClass {
public:MyClass(const MyClass& obj) {// 拷贝构造函数的实现}
};MyClass obj1;
MyClass obj2 = obj1;  // 调用拷贝构造函数

 2、当将一个对象作为函数参数传递给函数时,会调用拷贝构造函数。例如:

void func(MyClass obj) {// 函数体
}MyClass obj;
func(obj);  // 调用拷贝构造函数

3、当函数返回一个对象时,会调用拷贝构造函数。例如:

MyClass func() {MyClass obj;// 对 obj 进行初始化和操作return obj;  // 调用拷贝构造函数
}

需要注意的是,默认情况下,C++会生成一个默认的拷贝构造函数,该函数会将对象的所有成员变量进行一一拷贝。但如果类中存在指针或其他资源,需要手动编写拷贝构造函数来处理这些资源的拷贝问题,以防止浅拷贝带来的问题。

浅拷贝和深拷贝

C++中的拷贝操作有浅拷贝和深拷贝两种方式。

浅拷贝是指拷贝对象时,只是简单地将一个对象的数据成员的值复制给另一个对象的对应数据成员,而不会复制指向动态分配内存的指针。这意味着两个指针将指向同一块内存,当其中一个对象释放这块内存时,另一个对象的指针将成为悬空指针。例如:

class MyClass {
public:int* data;MyClass(const MyClass& other) : data(other.data) {// 拷贝构造函数的实现}
};MyClass obj1;
obj1.data = new int(5);MyClass obj2 = obj1;  // 浅拷贝delete obj1.data;  // 释放内存
cout << *obj2.data;  // 可能会输出无效的值

深拷贝是指拷贝对象时,除了复制数据成员的值外,还会为每个指针成员分配一块新的内存,并将源对象的值复制到新的内存中,以确保两个对象之间的指针成员指向不同的内存块。这样即使一个对象释放了内存,另一个对象的指针仍然有效。例如:

class MyClass {
public:int* data;MyClass(const MyClass& other) : data(new int(*other.data)) {// 拷贝构造函数的实现}~MyClass() {delete data;}
};MyClass obj1;
obj1.data = new int(5);MyClass obj2 = obj1;  // 深拷贝delete obj1.data;  // 释放内存
cout << *obj2.data;  // 仍然可以正常输出

析构函数

C++中的析构函数是一种特殊的成员函数,用于在对象的生命周期结束时执行清理操作。析构函数的名称与类的名称相同,前面加上一个波浪号(~)作为前缀,没有返回类型,也没有参数。

析构函数在以下情况下被调用:

  1. 当对象的作用域结束时,例如,当对象在函数中定义并在函数结束时销毁。
  2. 当对象是另一个对象的成员,并且该对象的析构函数被调用时。
  3. 当使用delete关键字显式释放通过new关键字配分的内存时。

析构函数的主要目的是释放对象分配的资源,例如动态分配的内存、打开的文件等。它可以通过在析构函数中使用delete关键字来释放内存,或者通过关闭文件句柄等操作来释放资源。

以下是一个示例,展示了一个类的析构函数的基本用法:

class MyClass {
public:MyClass() {cout << "构造函数被调用" << endl;}~MyClass() {cout << "析构函数被调用" << endl;}
};int main() {MyClass obj;  // 创建一个对象// 在此处执行其他操作return 0;  // 对象的作用域结束,析构函数被调用
}

当对象的作用域结束时,析构函数将被自动调用,输出如下结果:

构造函数被调用
析构函数被调用

需要注意的是,如果类中使用了动态分配的内存或其他资源,在析构函数中应该对这些资源进行释放,以避免内存泄漏或资源泄漏的问题。

 总结

构造函数

析构函数

创建对象时手动调用

当对象销毁时,自动调用

函数名称是类名

函数名称是~类名

构造函数可以重载

析构函数没有参数,不能重载

用于创建对象时并初始化

用于销毁对象时释放资源

有返回值但是不写,返回值是新创建的对象

没有返回值

练习一下ヽ( ̄▽ ̄)ノ 

写一个Dog类,要求有性别、年龄和品种三个属性,属性值封装,使用构造函数传参初始化。增加函数Dog* birth(const Dog& d),在函数体内部判断d与当前狗对象的属性值,当满足以下条件时,返回新创建的狗对象:

● 两条狗的年龄2-5

● 一公一母

新创建的狗对象的属性满足以下条件:

● 年龄:1岁

● 性别:随意

● 品种:

○ 如果父母的品种一样,品种就是父母的品种

○ 如果父母的品种不一样,品种是父母品种的拼合(自己制定拼合逻辑,或者直接是父母的品种之一)

如果两条狗不能生育,返回NULL。

参考代码

#include <iostream>
#include<string.h>
#include<time.h>
using namespace std;class Dog
{
private:int sex;  //0母 1公int age;  //小于2或大于5不能生育char *variety=new char[20];public:Dog(int s,int a,char *v){if(s==3) //  性别随机{sex=time(NULL)%2;}else{sex=s;}age=a;strcpy(variety,v);}Dog* brith(const Dog &D){if(sex != D.sex){if( age < 2 || age > 5 || D.age < 2 || D.age > 5 ){return NULL;}Dog* NewDog = new Dog(3,1,D.variety);return NewDog;}return NULL;}int get_sex(){return sex;}int get_age(){return age;}char *get_variety(){return variety;}};int main()
{int sex,age;char variety[20];while(1){cout << "请输入狗A的 性别(0:母 1:公) 年龄 品种" << endl;cin >> sex >> age >> variety;Dog dogA(sex,age,variety);cout << "请输入狗B的 性别(0:母 1:公) 年龄 品种" << endl;cin >> sex >> age >> variety;Dog dogB(sex,age,variety);Dog* NewDog=dogB.brith(dogA);if(NewDog==NULL){cout << "dogA和dogB无法生育" << endl;continue;}cout << "小狗的属性:" << endl;cout << "sex:" << NewDog->get_sex() << endl;cout << "age:" << NewDog->get_age() << endl;cout << "variety:" << NewDog->get_variety() << endl;}return 0;
}

相关文章:

从0开始C++(三):构造函数与析构函数详解

目录 构造函数 构造函数的基本使用 构造函数也支持函数重载 构造函数也支持函数参数默认值 构造初始化列表 拷贝构造函数 浅拷贝和深拷贝 析构函数 总结 练习一下ヽ(&#xffe3;▽&#xffe3;)&#xff89; 构造函数 构造函数的基本使用 构造函数是一种特殊的成…...

行车记录仪文件夹“0字节”现象解析与恢复策略

一、行车记录仪文件夹“0字节”现象描述 行车记录仪作为现代驾驶中的必备设备&#xff0c;其储存的视频数据对于事故记录和取证至关重要。然而&#xff0c;有时车主们可能会遇到这样一个问题&#xff1a;行车记录仪的某个文件夹内的文件突然变成了0字节大小&#xff0c;无法正…...

呼叫中心系统的功能都有哪些?okcc呼叫中心pscc磐石云呼叫系统部署

当前电话营销普及到各行各业&#xff0c;方便快捷成了大部分企业在宣传自己公司的产品时必用的一种营销方式&#xff0c;但是电话营销在管理上也存在许多问题。例如&#xff1a;销售员与客户沟通前&#xff0c;未能详细了解客户的资料&#xff1b;多名销售员重复拨打同一个客户…...

2024.06.08校招 实习 内推 面经

绿*泡*泡VX&#xff1a; neituijunsir 交流*裙 &#xff0c;内推/实习/校招汇总表格 1、提前批 | 中电锦江2025届提前批招聘 提前批 | 中电锦江2025届提前批招聘 2、实习 | 国电电力2025届暑期实习生计划启动&#xff01; 实习 | 国电电力2025届暑期实习生计划启动&#x…...

Polyplus——转染试剂专业供应商

PolyPlus-transfection是一家专业的转染试剂研发和生产的生物技术公司&#xff0c;拥有20年的的转染试剂研发经验&#xff0c;通过创新的核酸转染解决方案支持基因和细胞治疗、生物制剂制造和生命科学研究。目前已经通过了ISO 9001: 2000质量体系认证&#xff0c;已经开发了一系…...

微服务架构-线上治理、线下治理与架构演进

目录 一、线上治理 1.1 概述 1.2 线上预案体系 1.2.1 概述 1.2.2 变更引起的故障 1.2.3 流量和容量变化引起的故障 1.2.4 依赖故障 1.2.5 机房、网络等硬件和环境故障 1.2.6 其他 1.2.7 故障的场景化 1.3 基于Metric的预案自动触发 1.4 治理参数动态调整 1.4.1 举例…...

网络安全:什么是SQL注入

文章目录 网络安全&#xff1a;什么是SQL注入引言SQL注入简介工作原理示例代码 攻击类型为什么SQL注入危险结语 网络安全&#xff1a;什么是SQL注入 引言 在数字化时代&#xff0c;数据安全成为了企业和个人最关心的问题之一。SQL注入&#xff08;SQL Injection&#xff09;是…...

从零开始精通Onvif之网络配置

&#x1f4a1; 如果想阅读最新的文章&#xff0c;或者有技术问题需要交流和沟通&#xff0c;可搜索并关注微信公众号“希望睿智”。 概述 网络配置是Onvif规范中的重要组成部分&#xff0c;允许用户通过网络远程配置和管理设备的网络设置&#xff0c;比如&#xff1a;DHCP、IP地…...

在 macOS 上使用 Homebrew 安装和配置 Python 及 Tk 库

在 macOS 上&#xff0c;系统自带的 /usr/bin/python3 版本较旧&#xff0c;且直接升级系统自带的 Python 版本可能会影响系统稳定性。因此&#xff0c;推荐使用 Homebrew 来安装和管理 Python 及其相关库。本文将详细介绍如何通过 Homebrew 安装和配置 Python 3 及 Tk 库&…...

【机器学习 复习】第2章 线性回归及最大熵模型

一、概念 1.回归就是用一条曲线对数据点进行拟合&#xff0c;该曲线称为最佳拟合曲线&#xff0c;这个拟合过程称为回归。 2.一个自变量 叫 一元线性回归&#xff0c;大于一个自变量 叫 多元线性回归。 &#xff08;1&#xff09;多元回归&#xff1a;两个x&#xff0c;一个…...

关于椭圆的方程(有Python画的动图)

关于椭圆的方程&#xff08;有Python画的动图&#xff09; flyfish 几何定义 椭圆是平面上所有到两个固定点&#xff08;焦点&#xff09;的距离之和为常数的点的集合。这两个固定点叫做焦点。 解析几何描述 设椭圆的两个焦点为 F 1 F_1 F1​ 和 F 2 F_2 F2​&#xff…...

selenium常见难点解决方案

勾选框勾选问题 勾选框代码逻辑实现过程&#xff1a; 第一步&#xff1a;首先找到勾选框的元素&#xff1b; 第二步&#xff1a;检查它是否已经被勾选。如果已经勾选&#xff0c;则进行取消勾选操作&#xff1b;如果未勾选&#xff0c;则进行点击勾选操作&#xff1b; 以下是一…...

【Python高级编程】 综合练习-使用OpenCV 进行视频数据处理

综合练习 读取一个视频文件&#xff0c;对其进行处理后保存为一个新的视频文件。具体的处理步骤包括调整帧大小、转换为灰度图像、垂直翻转画面以及添加高斯噪声。 下面是代码的详细实现&#xff1a; import cv2 import numpy as np# 定义一个函数&#xff0c;用来给图像添加…...

rs232和can的区别

在电机通讯和升级固件时我们经常用到RS232和CAN两种通讯模式&#xff0c;那这两种有何不同吗&#xff1f; RS232和CAN的主要区别在于通信方式、应用场景、传输距离、通信速度以及网络结构。 通信方式&#xff1a; RS232是一种串行通信接口标准&#xff0c;支持全双工通信&…...

嵌入式软件stm32面试

一、STM32的内核型号有哪些&#xff1f; STM32系列是STMicroelectronics&#xff08;意法半导体&#xff09;生产的基于ARM Cortex-M内核的微控制器产品线。这些产品按照不同的内核架构和性能特点分为了主流产品、超低功耗产品和高性能产品。 1.1 主流产品 STM32F0 系列&…...

【Git】-- 添加公钥到 github 或者gitlab上

仅针对系统&#xff1a;mac os 、 unix、linux 1、检查是否有 id_rsa.pub $ cd ~ $ ls -al ~/.ssh 注意&#xff1a;若已有 id_rsa.pub&#xff0c;则必要执行 第二步&#xff0c;避免覆盖掉原有正常的公钥。 配置多个 git 账号请参考&#xff1a;同一台电脑配置多个git账…...

Vue页面生成PDF后调起浏览器打印

一、安装依赖 首先&#xff0c;需要安装 html2canvas 和 jsPDF 库。 npm install html2canvas jspdf二、创建公共方法引入 在utils文件夹下创建两个文件分别为pdfExport.js和printPDF.js&#xff0c;代码如下&#xff1a; pdfExport.js import html2canvas from html2canv…...

纯前端实现导出excel

项目背景&#xff1a; vue2 插件&#xff1a; xlsx&#xff1b;xlsx-style&#xff1b;file-saver 说明&#xff1a; 单独使用 xlsx插件&#xff0c;也可以将网页上的table导出成excel&#xff0c;但是导出的excel&#xff0c;没有样式 结合xlsx-style&#xff1b;file-saver&a…...

QT windows 5.12.0 安装包

这个是在线包&#xff0c;需要有账号的。 没有也没事&#xff0c;安装界面可以现场注册 百度网盘链接&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1QvXDert4b94GbUfD2f2G4g?pwd8888 提取码&#xff1a;8888...

改进YOLOv7 | 在 ELAN 模块中添加【Triplet】【SpatialGroupEnhance】【NAM】【S2】注意力机制 | 附详细结构图

改进 YOLOv7 | 在 ELAN 模块中添加【Triplet】【SpatialGroupEnhance】【NAM】【S2】注意力机制&#xff1a;中文详解 1. 简介 YOLOv7 是目前主流的目标检测算法之一&#xff0c;具有速度快、精度高的特点。但 YOLOv7 的原始模型结构中缺乏注意力机制&#xff0c;导致模型对全…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

逻辑回归:给不确定性划界的分类大师

想象你是一名医生。面对患者的检查报告&#xff08;肿瘤大小、血液指标&#xff09;&#xff0c;你需要做出一个**决定性判断**&#xff1a;恶性还是良性&#xff1f;这种“非黑即白”的抉择&#xff0c;正是**逻辑回归&#xff08;Logistic Regression&#xff09;** 的战场&a…...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

AGain DB和倍数增益的关系

我在设置一款索尼CMOS芯片时&#xff0c;Again增益0db变化为6DB&#xff0c;画面的变化只有2倍DN的增益&#xff0c;比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析&#xff1a; 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

C/C++ 中附加包含目录、附加库目录与附加依赖项详解

在 C/C 编程的编译和链接过程中&#xff0c;附加包含目录、附加库目录和附加依赖项是三个至关重要的设置&#xff0c;它们相互配合&#xff0c;确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中&#xff0c;这些概念容易让人混淆&#xff0c;但深入理解它们的作用和联…...

【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制

使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下&#xff0c;限制某个 IP 的访问频率是非常重要的&#xff0c;可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案&#xff0c;使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...

tomcat指定使用的jdk版本

说明 有时候需要对tomcat配置指定的jdk版本号&#xff0c;此时&#xff0c;我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...

深度剖析 DeepSeek 开源模型部署与应用:策略、权衡与未来走向

在人工智能技术呈指数级发展的当下&#xff0c;大模型已然成为推动各行业变革的核心驱动力。DeepSeek 开源模型以其卓越的性能和灵活的开源特性&#xff0c;吸引了众多企业与开发者的目光。如何高效且合理地部署与运用 DeepSeek 模型&#xff0c;成为释放其巨大潜力的关键所在&…...