从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;
}

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

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

相关文章

腾讯地图撒点并默认显示点位信息

实现步骤如下&#xff1a; 1、注册腾讯位置服务账号并获取 Key 2、需要创建一个地图容器&#xff0c;并使用腾讯地图的 API 初始化地图。通常涉及到设置地图的中心点、缩放级别和地图样式。 map new TMap.Map(document.getElementById(‘container’), { center: center, zo…

Vue56-组件的自定义事件

一、什么是自定义事件 二、子组件—【传值】—>父组件 2-1、prop属性 2-2、自定义事件 v-on在谁身上&#xff0c;就给谁绑定事件&#xff01; 给谁绑定的事件&#xff0c;想触发就找谁&#xff01; 2-3、prop属性VS自定义属性 2-4、简写形式 2-5、ref属性实现 加了ref属性…

软件监控发展简史

软件监控简史&#xff0c;从 00 年代开始。发生了什么变化&#xff1f;为什么事情变得如此神秘&#xff1f; 终端设备上日益重要的用户体验通过边缘计算和分布式计算不断得到改善。然而&#xff0c;服务质量的测量仍然使用基于服务器的原语进行。 我们的 2000 年软件监控是这样…

程序员兼职接单有哪些渠道?一篇文章带你了解!

2024年&#xff0c;程序员兼职接单别只盯着朋友圈啦&#xff01;这些兼职接单渠道你一个都不容错过&#xff01;想要通过兼职接单获取收入的程序员&#xff0c;一定不能错过这篇文章&#xff01; 程序员兼职接单的渠道可以简单的分类为兼职平台和程序员论坛和自身人脉拓展三个…

【SD3辅助工具推荐】InstantX发布了三种SD3专属的ControlNet模式——Pose、Canny和Tile

InstantX 是一家专注于人工智能内容生成的独立研究机构。此前&#xff0c;曾开源著名的InstantID和论文《InstantID : Zero-shot Identity-Preserving Generation in Seconds》。随着本月12号&#xff0c;Stability AI正式开源了其产品 Stable Diffusion 3&#xff0c;这家机构…

高效设计必选!5款好用的UI动效工具

UI 动态设计是应用程序设计的重要组成部分。随着技术的积累&#xff0c;UI设计中的动态效果遍地开花&#xff0c;UI动态效果可以使我们的页面更时尚、更有趣、更人性化。5G网络的快速发展也使美丽的动态效果几乎无缝地嵌入到UI界面中。今天&#xff0c;毫不夸张地说&#xff0c…

Visual Studio2022+cuda环境配置及代码调试

环境配置 下载并安装CUDA Toolkit 打开Visual Studio&#xff0c;新建项目。如下图所示&#xff0c;已经包含CUDA编程选项 代码调试 1、打开cu文件的属性页&#xff0c;按下图所示&#xff0c;将Host中的Generate Host Debug Information设置为“是" 2、不可勾选Nsight…

ARM功耗管理框架之LPI

安全之安全(security)博客目录导读 思考&#xff1a;功耗管理框架&#xff1f;SCP&#xff1f;PPU&#xff1f;LPI&#xff1f;之间的关系&#xff1f;如何配合&#xff1f; 目录 一、功耗管理框架中的LPI 二、LPI分类 三、Q-Channel和P-Channel对比 四、Q-Channel和P-Ch…

第28讲:Ceph集群使用RBD块存储与K8S Volumes集成

文章目录 1.Ceph集群使用RBD块存储与K8S集成简介2.Ceph集群RBD块存储与K8S Volume集成2.1.在Ceph集群中创建K8S集群使用的块存储2.2.创建用于K8S访问Ceph RBD块设备的认证用户2.3.将认证用户的Key存储在K8S Secret资源中2.4.在K8S集群的所有节点中安装Ceph命令2.5.创建Pod资源使…

【uni-app学习手札】

uni-app&#xff08;vue3&#xff09;编写微信小程序 编写uni-app不必拘泥于HBuilder-X编辑器&#xff0c;可用vscode进行编写&#xff0c;在《微信开发者工具》中进行热加载预览&#xff0c; 主要记录使用uni-app过程中自我备忘一些api跟语法&#xff0c;方便以后编写查找使用…

【React 】折叠面板,点击展开时再请求数据

需求背景&#xff1a;使用折叠面板的形式展示数据&#xff0c;面板内部数据需要在打开时请求接口获取。 遇到问题&#xff1a;最开始使用Antd 的折叠面板组件&#xff0c;它对于数据直接渲染是没问题的&#xff0c;但是不好满足打开面板时再动态加载数据的需求&#xff0c;于是…

JAVA中EasyPoi导出word文档附带表格数据

导入easy-poi相关依赖 <!-- word导出 方式&#xff1a;easypoi --><dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-base</artifactId><version>4.4.0</version></dependency><dependency><…

VBA学习(12):制作动态模糊匹配的下拉菜单

今天就再给大家分享一下&#xff0c;如何使用VBA制作更好用的动态模糊匹配下拉菜单。 完成后的效果演示如下&#xff1a; 如上图所示&#xff0c;点击A列单元格&#xff0c;Excel会自动跳出一个文本输入框和一个列表框。当在文本框中输入数据时&#xff0c;列表框的数据会随之…

IIS代理配置-反向代理

前后端分离项目&#xff0c;前端在开发中使用proxy代理解决跨域问题&#xff0c;打包之后无效。 未配置前无法访问 部署环境为windows IIS&#xff0c;要在iis设置反向代理 安装代理模块 需要在iis中实现代理&#xff0c;需要安装Application Request Routing Cache和URL重…

思维导图之计算机网络整体框架

高清自行访问&#xff1a;计算机网络整体框架 (yuque.com)

南开大学漏洞报送证书

获取来源&#xff1a;edusrc&#xff08;教育漏洞报告平台&#xff09; url&#xff1a;教育漏洞报告平台(EDUSRC) 兑换价格&#xff1a;30金币​ 获取条件&#xff1a;南开大学任意中危或以上级别漏洞 证书规格&#xff1a;证书做了木框装裱&#xff0c;显得很高级

k8s自动补全工具和UI管理界面

分享两个有利于K8S的工具 目录 分享两个有利于K8S的工具 一、部署Dashboard&#xff08;主节点&#xff09; 介绍 1.1、查看集群状态 1.2、下载yaml文件并运行Dashboard 1.3、部署服务 1.4、创建访问账户、获取token&#xff08;令牌&#xff09; 1.5、浏览器访问Dash…

EasyCVR/EasyDSS无人机直播技术助力野生动物监测

近日有新闻报道&#xff0c;一名挖掘机师傅在清理河道时&#xff0c;意外挖出一只稀有的扬子鳄&#xff0c;挖机师傅小心翼翼地将其放在一边&#xff0c;扬子鳄也顺势游回一旁的河道中。 随着人类对自然环境的不断探索和开发&#xff0c;野生动物及其栖息地的保护显得愈发重要。…

天池人脸识别项目复现

1 项目背景 #c 概述 项目的目的 图像分类是整个计算机视觉领域中最基础的任务&#xff0c;也是最重要的任务之⼀&#xff0c;最适合拿来进⾏学习实践。为了让新⼿们能够⼀次性体验⼀个⼯业级别的图像分类任务的完整流程&#xff0c;本次我们选择带领⼤家完成⼀个对图片中⼈脸进…

【Tableau系列第(6)篇】使用Tableau Prep进行数据清理、整合(一)

使用Tableau Prep的整体过程详见&#xff1a;【Tableau系列第&#xff08;5&#xff09;篇】用Tableau Prep整理数据全流程初体验 本篇一步一步跟我一起来熟悉更多的Tableau Prep数据清理、整合的操作。 示例excel数据源链接: https://pan.baidu.com/s/17nx3_LPe30oK1l1JsC6K…