c++——类和对象(1)构造,析构函数

类的六个默认函数

如果一个类当中没有成员的话,那叫空类,实际上空类有6个编译器默认生成的函数成员

默认成员函数:没有显示实现,编译器生成的成员函数称为默认成员函数

1,构造函数与构析函数

1.1构造函数的概念

构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,以

保证 每个数据成员都有 一个合适的初始值,并且在对象整个生命周期内只调用一次。

1.2构造函数的特性

构造函数主要任务是初始化对象,并不是开辟空间

1. 函数名与类名相同。

2. 无返回值。

3. 对象实例化时编译器自动调用对应的构造函数。

4. 构造函数可以重载。

class Data {
public:
//无参构造函数Data(){_year = 1;_month = 1;_day = 1;}
//含参构造函数Data(int year, int month, int day){_year = year;_month = month;_day = day;}
//全缺省函数Data(int year = 2, int month = 2, int day = 2){}void printf(){cout << _year << _month << _day << endl;//崩溃,cout << "printf()" << endl;//正常}
private:int _year;int _month;int _day;
};
int main()
{Data d1;d1.printf();Data d2(2024, 2, 2);d2.printf();Data d3;d3.printf();return 0;
}

4.1无参构造函数与含参构造函数的使用,无参函数直接Data d1;不加括号为了

避免重复声明新函数

Data d1;
d1.printf();
Data d2(2024, 2, 2);
d2.printf();

4.2全缺省函数与无参构造函数,d1与d3构成重载函数,但下面会构成重载失误

Data d1;
d1.printf();Data d3;
d3.printf();//d3与d1构成重载,

会出现下面错误

5. 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦 用户显式定义编译器将不再生成。

6. C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类 型,如:int/char...,自定义类型就是我们使用class/struct/union等自己定义的类型,看看 下面的程序,就会发现编译器生成默认的构造函数会对自定类型成员_t调用的它的默认成员 函数。

class Time {
public:Time(){cout << "time()" << endl;_hour = 0;_minute = 0;}
private:int _hour;int _minute;
};
class Data
{
public:private:int _year;int _month;int _day;Time _t;
};
int main()
{Data d;return 0;
}

上面的代码的处理结果是内置类型不一会被处理(具体看编译器vs不会处理),而自定义类型会被处理,Time是自定义类型所以会初始化

但只有是无参构造函数才会成功,若有参数会报错Time(int a){}

1.3析构函数的概念

析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由 编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。

1.4析构函数的特性

1. 析构函数名是在类名前加上字符 ~。

2. 无参数无返回值类型。

3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构 函数不能重载

4. 对象生命周期结束时,C++编译系统系统自动调用析构函数

typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 3){_array = (DataType*)malloc(sizeof(DataType) * capacity);if (NULL == _array){perror("malloc申请空间失败!!!");return;}_capacity = capacity;_size = 0;}void Push(DataType data){// CheckCapacity();_array[_size] = data;_size++;}// 其他方法...~Stack(){if (_array){free(_array);_array = NULL;_capacity = 0;_size = 0;}}
private:DataType* _array;int _capacity;int _size;
};
void TestStack()
{Stack s;s.Push(1);s.Push(2);
}

如果像这一类,申请了空间,没有调用显示析构函数,会有内存泄漏的风险,所以如果有类调用堆上的空间,一定要调用析构函数

2,拷贝构造函数

2,1概念

拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存 在的类类型对象创建新对象时由编译器自动调用。

2.2特性

1, 拷贝构造函数的参数只有一个

2参数必须是类类型对象的引用,使用传值方式编译器直接报错, 因为会引发无穷递归调用。

class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}// Date(const Date& d)   // 正确写法Date(const Date& d)   // 错误写法:编译报错,会引发无穷递归{_year = d._year;_month = d._month;_day = d._day;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;Date d2(d1);return 0;
}

因为传值会调用拷贝构造函数,造成无限递归,所以用引用

3. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按 字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。

4类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请 时,则拷贝构造函数是一定要写的,否则就是浅拷贝。

typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 10){_array = (DataType*)malloc(capacity * sizeof(DataType));if (nullptr == _array){perror("malloc申请空间失败");return;}_size = 0;_capacity = capacity;}void Push(const DataType& data){// CheckCapacity();_array[_size] = data;_size++;}~Stack(){if (_array){free(_array);_array = nullptr;_capacity = 0;_size = 0;}}
private:DataType *_array;size_t _size;size_t _capacity;
};
int main()
{Stack s1;s1.Push(1);s1.Push(2);s1.Push(3);s1.Push(4);Stack s2(s1);return 0;
}

这是为什么,是因为浅拷贝是在同一块空间,如果创建两个对象,s1,s2,都指向同一内存,调用析构函数时,会将同一块空间free两次,造成错误

5. 拷贝构造函数典型调用场景:

  1. 使用已存在对象创建新对象
  2. 函数参数类型为类类型对象
  3. 函数返回值类型为类类型对象
class Date {
public:Date(int year,int month,int day){cout << "Data()"<<endl;_year = year;_month = month;_day = day;}~Date(){cout << "~Data()"<<endl;}Date(const Date& d){cout << "Date(const Date&d)"<<endl;_year = d._year;_month = d._month;_day = d._day;}private:int _year;int _month;int _day;};
Date test(Date d1)
{Date tem(d1);第二次拷贝构造return tem;//本来是第三次拷贝构造,但被编译被优化了因为第二次拷贝构造的值可以做返回值
}
int main()
{Date d1(2024, 2, 1);test(d1);//第一次拷贝构造函数return 0;
}

下面是结果

6.传值与引用的细分

1传值会多拷贝一次,比较麻烦,但是可以避免一些错误

2而引用虽然方便但是会有一些情况出问题;

 class Date {public:Date(int year,int month,int day){cout << "Data()"<<endl;_year = year;_month = month;_day = day;}~Date(){cout << "~Data()"<<endl;_year = -1;_month = -1;_day = -1;}Date(const Date& d){cout << "Date(const Date&d)"<<endl;_year = d._year;_month = d._month;_day = d._day;}Date operator=(const Date& d){_year = d._year;_month = d._month;_day =d._day;//this是d2的形参,d是_d4//然后d1是this的位置,d2是d4return *this;}void printf(){cout << _year <<" " << _month <<" " << _day << endl;}private:int _year;int _month;int _day;};Date& fun(){Date d(1, 2, 2);return d;}void func(){}int main(){Date d1(2024, 4, 14);Date d2(d1);Date d3 = d1;//拷贝构造,把存在的拷贝给不存在的Date d4(2024, 5, 1);d1= d4;//赋值重载,不会调用拷贝构造函数//连续赋值d1 = d2 = d4;//到这一行总共5个调用拷贝,但是把上面的变成引用返回,只有两个
return 0;}

下面是结果

但是如果是引用的话

下面是一些错误的发生

 Date& fun(){Date d(1, 2, 2);return d;}int main(){Date& ret = fun();ret.printf();return 0;}

因为return d前先析构,再返回,本来是调试看到析构后this是随机值是野空间,如果下面在调用一个函数,就会可能会变野空间会  变化,随机值被改变
 

总 结  返回对象是临时对象,或局部变量不用引用返回,有风险
 1如果返回对象生命周期到了,不会析构,可以用传引用返回uobuyi

创作不易,希望点赞!!!

目录

类的六个默认函数

1,构造函数与构析函数

2,拷贝构造函数


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

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

相关文章

【MATLAB源码-第194期】基于matlab的MB-OFDM仿真,超宽带(UWB)无线传输。对比LS/DFT及其改进算法。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 一、无线通信的基本原理 无线通信是通过空气或其他介质传播电磁波来传输信息的技术。这种通信方式的核心在于电磁波&#xff0c;它能够在没有物理连接的情况下传输数据。无线通信的基本流程包括&#xff1a; 信号的生成&am…

python使用uiautomator2操作真机(oppo a9x)

环境&#xff1a; python3.8.10&#xff0c;oppo a9x(6G,128g)&#xff0c;版本android 11。 之前写过文章&#xff1a; python使用uiautomator2操作真机&#xff08;荣耀10青春版&#xff09;_python uiautomator2 控制真机-CSDN博客 python使用uiautomator2操作真机&…

c语言之字符串的集合存放形式

采用指针分配的二维数组与直接定义的二维数组&#xff0c;sizeof的不同 采用指针分配的二维数组&#xff1a; 它的遍历方式是&#xff1a; 上面这个是分配二级指针的地址&#xff0c;二级指针就是一片可以用来分配一级指针空间的地址&#xff0c;然后指针寻址本来就可以当成数组…

K8s 部署 MySQL 8.0.20 主从复制结构

一、K8s 部署 MySQL 安装规划 组件replicas类型mysql-master1StatefulSetmysql-slave1StatefulSet 使用 k8s 版本为&#xff1a;v1.18.0 。 本次使用 OpenEBS 来作为存储引擎&#xff0c;OpenEBS 是一个开源的、可扩展的存储平台&#xff0c;它提供了一种简单的方式来创建和…

老阳闲聊|怎么在Temu电商平台上赚钱?

随着互联网技术的飞速发展&#xff0c;电商平台如雨后春笋般涌现&#xff0c;其中Temu电商平台以其独特的商业模式和广阔的市场前景&#xff0c;吸引了众多创业者和商家的目光。那么&#xff0c;如何在Temu电商平台上赚钱呢?本文将为您详细解析。 首先&#xff0c;了解Temu电商…

(2022级)成都工业学院数据库原理及应用实验七: 数据库安全

写在前面 1、基于2022级软件工程/计算机科学与技术实验指导书 2、成品仅提供参考 3、如果成品不满足你的要求&#xff0c;请寻求其他的途径 运行环境 window11家庭版 Navicat Premium 16 Mysql 8.0.36 实验要求 1、创建数据库hospital,在hospital数据库中创建科室表De…

【C++】日期类Date(详解)

&#x1f525;个人主页&#xff1a;Forcible Bug Maker &#x1f525;专栏&#xff1a;C 目录 前言 日期类 日期类实现地图 获取某年某月的天数&#xff1a;GetMonthDay 检查日期合法&#xff0c;构造函数&#xff0c;拷贝构造函数&#xff0c;赋值运算符重载及析构函数…

21.组件组成

组件组成 组件最大的优势就是可复用性 当使用构建步骤时&#xff0c;我们一般会将 Vue 组件定义在一个单独的 .vue 文件中&#xff0c;这被叫做单文件组件(简称 SFC) 组件组成结构 <template><div>承载标签</div> </template> <script> expor…

【Java并发知识总结 | 第七篇】Java并发相关概念总结(程序/进程/线程、并行/并发、同步/异步、死锁/避免、线程安全/三大特性)

文章目录 7.并发相关概念总结&#xff08;程序/进程/线程、并行/并发、同步/异步、死锁/避免、线程安全/三大特性&#xff09;7.1程序、进程与线程7.2并行和并发7.3同步和异步7.4什么是死锁&#xff1f;如何避免&#xff1f;7.5何为线程安全&#xff1f;以及三大特性 7.并发相关…

SQL 语言数据操纵语言 DML

一、目的 SQL 语言的数据操纵功能通过 DML(数据维护语言)实现。DML 包括数据查 询和数据更新两种数据操纵语句。其中&#xff0c;数据查询指对数据库中的数据查询、统 计、分组、排序等操作&#xff1b;数据更新指数据的插入、更新和删除等数据维护操 作。 本次实验了解 D…

2023年图灵奖颁给普林斯顿数学教授 Avi Wigderson

2023年图灵奖揭晓&#xff0c;你怎么看&#xff1f; 什么是图灵奖 图灵奖&#xff08;Turing Award&#xff09;&#xff0c;全称A.M.图灵奖&#xff08;ACM A.M Turing Award&#xff09;&#xff0c;是由美国计算机协会&#xff08;ACM&#xff09;于1966年设立的计算机奖项…

谷歌Gemini 1.5 Pro国内怎么用?国内镜像来了

长期以来&#xff0c;许多人向我咨询是否存在一个稳定而高效的全球AI大模型测试平台&#xff0c;这个平台需要不仅真实可靠&#xff0c;而且能够提供稳定和快速的服务&#xff0c;不会频繁出现故障或响应缓慢的问题。然而&#xff0c;当我发现了AskManyAI时&#xff0c;我被其所…