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

C++类和对象中上篇

1.类的6个默认成员函数

如果一个类中什么成员都没有,那就简称他为空类

空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。

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

class Date{ };

 构造函数

概念:

对于下面的一个Date类来说:

#include<iostream>
using namespace std;class Date
{
public:void Init(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}private:int _year;int _month;int _day;
};int main()
{Date d1;d1.Init(2024, 4, 12);d1.Print();Date d2;d2.Init(2024, 4, 123);d2.Print();return 0;
}

上述的Date类,在创建完对象后,可以通过Init的public即公有方法给日期设置对象,但如果每次创建对象时都调用该方法设置信息,肯定太麻烦了,那么有没有一个解决办法就是在创建对象时,就将信息设置进去的方法呢。

这个时候就有引入析构函数的概念了。析构函数是一个特殊的成员函数,名字与类相同,创建类类型对象时由编译器自动调用,以保证每个数据成员都有一个合适的初始值,并且在对象整个生命周期内只调用一次。

特性

构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象,而是初始化对象。

构造函数所有的前5个特性:

1.函数名与类名相同。

2.无返回值。

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

4.构造函数可以重载。

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

构造函数可以重载的例子。

#include<iostream>
using namespace std;
class Date
{
public://1.无参的构造函数Date(){}//2.有参数的构造函数Date(int year, int month, int day){_year = year;_month = month;_day = day;}private:int _year;int _month;int _day;
};int main()
{Date d1;//调用无参构造函数Date d2(2024, 4, 12);//调用带参的构造函数//注意:如果通过无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明//以下代码的函数:声明了d3函数,该函数无参,返回一个日期类型的对象。//warning C4930:"Date d3(void)":没有调用原型函数(是否是有意用变量定义的?)Date d3();return 0;
}

对于上述第5点的例子:


#include<iostream>
using namespace std;
class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}private:int _year;int _month;int _day;
};int main()
{//将Date类中构造函数屏蔽后,代码可以通过编译,因为编译器生成了一个无参的默认构造函数//将Date类中构造函数放开,代码编译失败Date d1;return 0;
}

构造函数的第6个特性:

关于编译器生成的默认成员函数,很多人都有疑惑:在不实现构造函数的情况下,编译器会生成默认的构造函数。但是看起来默认构造函数又没什么用?d对象调用了编译器生成的默认构造函数,但是d对象_year/_month/_day,依旧是随机值。也就是说在这里编译器生成的默认构造函数并没有什么用?

#include<iostream>
using namespace std;
class Time
{
public:Time(){cout << "Time()" << endl;_hour = 0;_minute = 0;_second = 0;}
private:int _hour;int _minute;int _second;
};class Date
{
private://基本类型(内置类型)int _year;int _month;int _day;//自定义类型Time _t;
};int main()
{Date d;return 0;
}

注意:C++11中针对内置类型成员不初始化的缺陷,又打了补丁,即:内置类型成员变量在类中声明时可以给默认值。

class Date
{
private://基本类型(内置类型)int _year=2024;int _month=4;int _day=12;//自定义类型Time _t;
};int main()
{Date d;return 0;
}

构造函数的第7个特性:

无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。

注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认构造函数。

class Date
{
public:Date(){_year = 2024;_month = 4;_day = 12;}Date(int year = 2024, int month = 1, int day = 1){_year = year;_month = month;_day = day;}private:int _year;int _month;int _day;
};//下面这个函数能够通过编译吗?
int main()
{Date d1; //对重载函数的调用不明确return 0;
}

上述测试报错,因为对重载函数的调用不明确,再掉无参时或者再调用有全缺省的不传参时,就会发生这种冲突。

析构函数

概念

刚才讲解了构造函数,因此我们知道了一个对象是怎么来的,那一个对象又是怎么没的呢?

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

特性

析构函数是特殊的成员函数,其特征如下:

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

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

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

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

#include<iostream>
#include<stdlib.h>
using namespace std;
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(){cout << "调用了析构函数" << endl;if (_array){free(_array);_array = NULL;_capacity = 0;_size = 0;}}private:DataType* _array;int _capacity;int _size;
};
int main()
{Stack s;s.Push(1);s.Push(2);return 0;
}

析构函数的第5个特性:

关于编译器自动生成的析构函数,是否会完成一些事情呢?下面的程序我们会看到,编译器生成的默认析构函数,对自定类型成员调用它的析构函数。

#include<iostream>
using namespace std;
class Time
{
public:~Time(){cout << "~Time()" << endl;}
private:int _hour;int _minute;int _second;
};class Date
{
private://基本类型(内置类型)int _year = 2024;int _month = 4;int _day = 1;//自定义类型Time _t;
};int main()
{Date d;return 0;
}
//程序运行结束后输出:~Time()
//在main方法中根本没有直接创建Time类的对象,为什么最后会调用Time类的对象,为什么最后会调用Time类的析构函数?
//因为:main方法中创建了Date对象d,而d中包含了4个成员变量,其中_year, _month, _day三个是
// 内置类型成员,销毁时不需要资源清理,最后系统直接将其内存回收即可;而_t是Time类对
//象,所以在d销毁时,要将其内部包含的Time类的_t对象销毁,所以要调用Time类的析构函数。但是:main函数
// 中不能直接调用Time类的析构函数,实际要释放的是Date类对象,所以编译器会调用Date类的析构函
// 数,而Date没有显式提供,则编译器会给Date类生成一个默认的析构函数,目的是在其内部调用Time// 类的析构函数,即当Date对象销毁时,要保证其内部每个自定义对象都可以正确销毁
// 注意:创建哪个类的对象则调用该类的析构函数,销毁那个类的对象则调用该类的析构函数

析构函数的第6个特性:

如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如
Date 类;有资源申请时,一定要写,否则会造成资源泄漏,比如 Stack 类。

拷贝构造函数 

概念:

在现实生活中,可能存在一个与你一样的自己,我们称其为双胞胎。

所以在创建对象时,能不能创建一个与已经存在的对象一模一样的新对象呢?

拷贝构造函数:

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

特征

拷贝构造函数也是特殊的成员函数,其特征如下:

1.拷贝构造函数是构造函数的一个重载形式。

2.拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。

class Date
{
public:Date(int year = 2024, int month = 4, int day = 13){_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.若没有显式定义,编译器会生成默认的拷贝构造函数。默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。

#include<iostream>
using namespace std;
class Time
{
public:Time(){_hour = 1;_minute = 1;_second = 1;}Time(const Time& t){_hour = t._hour;_minute = t._minute;_second = t._second;cout << "Time::Time(const Time&)" << endl;}
private:int _hour;int _minute;int _second;
};class Date
{
private://基本类型(内置类型)int _year = 2024;int _month = 4;int _day = 1;//自定义类型Time _t;
};int main()
{Date d1;// 用已经存在的d1拷贝构造d2,此处会调用Date类的拷贝构造函数// 但Date类并没有显式定义拷贝构造函数,则编译器会给Date类生成一个默认的拷贝构造函数Date d2(d1);return 0;
}

 注意:在编译器生成的默认拷贝构造函数中,内置类型是按照字节方式直接拷贝的,而自定义类型是调用其拷贝构造函数完成拷贝的。

4.编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了,还需要自己显式实现吗?

当然像日期类这样的类是没有必要的,下面的类来进行验证一下。

//这里发现这个程序会直接崩掉,这里需要我们以后讲的深拷贝去解决。
#include<iostream>
using namespace std;
typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 10){_array = (DataType*)malloc(capacity * sizeof(DataType));if (_array==nullptr){perror("malloc申请空间失败");return;}_size = 0;_capacity = capacity;}void Push(const DataType& data){//检查扩容_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;
}

 

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

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

使用已存在对象创建新对象

函数参数类型为类类型对象

函数返回值类型为类类型对象

#include<iostream>
using namespace std;
class Date
{
public:Date(int year, int minute, int day){cout << "Date(int,int,int):" << this << endl;}Date(const Date& d){cout << "Date(const Date& d):" << this << endl;}~Date(){cout << "~Date():" << this << endl;}
private:int _year;int _month;int _day;
};
Date Test(Date d)
{Date temp(d);return temp;
}
int main()
{Date d1(2024, 4, 13);Test(d1);return 0;
}

 为了提高程序效率,一般对象传参时,尽量使用引用类型,返回是根据实际场景,能用引用尽量使用引用。

相关文章:

C++类和对象中上篇

1.类的6个默认成员函数 如果一个类中什么成员都没有&#xff0c;那就简称他为空类。 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何类在什么都不写时&#xff0c;编译器会自动生成以下6个默认成员函数。 默认成员函数&#xff1a;用户没有显式实现&#xff0c;…...

基于linux进一步理解核间通讯

芯片架构分为同构和异构: 如下图TC397: 如下图TDA4: 如下图STM32MP157: 非对称多处理结构(AMP): AMP 结构是指每个内核运行自己的 OS 或同一 OS 的独立实例&#...

应用实战|从头开始开发记账本2:基于模板快速开始

上期视频我们创建好了BaaS服务的后端应用。从这期视频开始&#xff0c;我们将从头开发一个互联网记账本应用。本期视频我们介绍一下如何使用模板快速开启我们的应用开发之旅。 应用实战&#xff5c;从头开始开发记账本2&#xff1a;基于模板快速开始 相关代码 本期视频我们介绍…...

学习前端第二十天(条件分支:if 和 ‘?‘;逻辑运算符)

一、条件分支 if (…) 语句会计算圆括号内的表达式&#xff0c;并将计算结果转换为布尔型。 if(...) 语句计算括号里的条件表达式&#xff0c;如果计算结果是 true&#xff0c;就会执行对应的代码块{ }。 if 语句有时会包含一个可选的 “else” 块。如果判断条件不成立&…...

C++11的更新介绍(lamada、包装器)

&#x1fa90;&#x1fa90;&#x1fa90;欢迎来到程序员餐厅&#x1f4ab;&#x1f4ab;&#x1f4ab; 主厨&#xff1a;邪王真眼 主厨的主页&#xff1a;Chef‘s blog 所属专栏&#xff1a;c大冒险 总有光环在陨落&#xff0c;总有新星在闪烁 lambda表达式 C98中的一个…...

Golang 实现一个简单的 RPC 服务

分享一个简单的 rpc 服务框架 一、服务端实现 package mainimport ("log""net""net/rpc" )const HelloServiceName "main.HelloService"type HelloServiceInterface interface {Hello(request string, replay *string) error }func…...

Linux系统(centos,redhat,龙芯,麒麟等)忘记密码,怎么设置新的密码

Linux系统&#xff08;centos,redhat,龙芯&#xff0c;麒麟等&#xff09;忘记密码&#xff0c;怎么设置新的密码 今天在操作服务器时&#xff0c;DBA忘记了人大金仓数据库的kingbase密码&#xff0c;他的密码试了好多遍&#xff0c;都不行。最后只能给重置密码了 解决办法&a…...

SpringBoot的启动原理

运行Main方法&#xff1a; 应用程序启动始于Main方法的执行。在Main方法中&#xff0c;创建了一个SpringApplication实例&#xff0c;用于引导应用程序的启动。同时&#xff0c;SpringApplication会根据spring.factories文件加载并注册监听器、ApplicationContextInitializer等…...

git查看单独某一个文件的历史修改记录

git查看单独某一个文件的历史修改记录 git log -p 文件具体路径 注意&#xff0c;Windows下默认文件路径分隔符是 \&#xff0c;在git bash 里面需要改成 /。 git基于change代码修改与提交_git change-CSDN博客文章浏览阅读361次。git cherry-pick&#xff1a;复制多个提交comm…...

一键开启Scrum回顾会议的精彩时刻

其实回顾会议作为一个检视、反馈、改进环节&#xff0c;不仅在传统的瀑布管理模式中&#xff0c;还是在Scrum一类的敏捷管理流程中&#xff0c;都是非常重要的活动。一些团队认为它无法产生直接的价值&#xff0c;所以有意忽略了这个会议&#xff1b;一些团队在越来越多的回顾中…...

Python计算多个表格中多列数据的平均值与标准差并导出为新的Excel文件

本文介绍基于Python语言&#xff0c;对一个或多个表格文件中多列数据分别计算平均值与标准差&#xff0c;随后将多列数据对应的这2个数据结果导出为新的表格文件的方法。 首先&#xff0c;来看一下本文的需求。现有2个.csv格式的表格文件&#xff0c;其每1列表示1个变量&#x…...

nginx支持的多种负载均衡策略

目录 1.轮询&#xff08;默认&#xff09; 2. ip_hash 3. 加权轮询&#xff08;weight&#xff09; 4. fair&#xff08;第三方&#xff09; 5. 最少连接&#xff08;least_conn&#xff09; 1.轮询&#xff08;默认&#xff09; 将请求依次分配给每个服务器&#xff0c;确…...

FNP preptool has not been run on this executable

pycharm导入arcgis pro的python运行程序后提示 我也看了很多解决方法&#xff0c;也重新安装过一遍&#xff0c;终于看到一个说法是你的arcgis pro是学习版所以才会有这个提示&#xff0c;不会影响输入 测试代码 import arcpy print(arcpy.GetInstallInfo()[Version])输出结果…...

算法-反转单向链表

需求 思路 链表必有节点&#xff0c;节点两要素&#xff1a;当前元素值&#xff0c;下一个节点地址 import java.util.Scanner;// 定义一个单向链表 public class MyLinkedList<E> {int size 0;// 顶一个私有的内部类&#xff0c;表示链表的节点public class Node {E da…...

Ps 滤镜:方框模糊

Ps菜单&#xff1a;滤镜/模糊/方框模糊 Filter/Blur/Box Blur 方框模糊 Box Blur滤镜通过计算图像中每个像素及其周围像素的平均颜色值来实现模糊效果。适合于需要突出主题、减少背景&#xff08;尤其是颜色变化&#xff09;干扰的场景。 “方框模糊”滤镜按照设定的半径值&…...

MTK Android13 霸屏实现

一、背景 在台式POS场景下&#xff0c;经常有应用会需要获取霸屏的权限&#xff0c;隐藏状态栏或者导航栏&#xff0c;且不能被划出&#xff0c;其实系统已经系统了隐藏状态栏也导航栏的接口&#xff0c;但是无法做到禁止滑出。 View decorView ((Activity) context).getWin…...

PyTorch神经网络打印存储所有权重+激活值(运行时中间值)

很多时候嵌入式或者新硬件需要纯净的权重模型和激活值&#xff08;运行时中间值&#xff09;&#xff0c;本文提供一种最简洁的方法。 假设已经有模型model和pt文件了&#xff0c;在当前目录下新建weights文件夹&#xff0c;运行这段代码&#xff0c;就可以得到模型的权重&…...

grpc-教程(golang版)

目录 一、介绍 二、环境准备 三、Golang中使用grpc 1.编写protobuf文件 2.服务端 3.客户端 四、proto文件详解 1.proto语法 2.数据类型 基本数据类型 数组类型 map类型 嵌套类型 编写风格 3.多服务 4.多个proto文件 五、流式传输 1.普通rpc 2.服务器流式 …...

Spring与Spring Boot的区别:从框架设计到应用开发

这是我自己开发的一款小程序&#xff0c;感兴趣的可以体验一下&#xff1a; 进入正题&#xff1a; 在Java开发领域&#xff0c;Spring和Spring Boot都是备受推崇的框架&#xff0c;它们为开发人员提供了丰富的功能和便捷的开发体验。然而&#xff0c;许多人对它们之间的区别仍…...

React Hooks 全解: 常用 Hooks 及使用场景详解

React Hooks 是 React 16.8 版本引入的一项重要特性,它极大地简化和优化了函数组件的开发过程。 React 中常用的 10 个 Hooks,包括 useState、useEffect、useContext、useReducer、useCallback、useMemo、useRef、useLayoutEffect、useImperativeHandle 和 useDebugValue。这些…...

JiYuTrainer:如何一键解除极域电子教室的全屏控制限制?

JiYuTrainer&#xff1a;如何一键解除极域电子教室的全屏控制限制&#xff1f; 【免费下载链接】JiYuTrainer 极域电子教室防控制软件, StudenMain.exe 破解 项目地址: https://gitcode.com/gh_mirrors/ji/JiYuTrainer 你是否曾在机房上课时&#xff0c;被极域电子教室的…...

颠覆式突破:无需模拟器,在Windows系统上直接运行Android应用的革命性方案

颠覆式突破&#xff1a;无需模拟器&#xff0c;在Windows系统上直接运行Android应用的革命性方案 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 想象一下&#xff0c;…...

如何零配置搭建专业级视觉交互系统:MediaPipe TouchDesigner完全指南

如何零配置搭建专业级视觉交互系统&#xff1a;MediaPipe TouchDesigner完全指南 【免费下载链接】mediapipe-touchdesigner GPU Accelerated MediaPipe Plugin for TouchDesigner 项目地址: https://gitcode.com/gh_mirrors/me/mediapipe-touchdesigner 想要在TouchDes…...

从热电偶到串口显示:用STM32F103C8T6+MAX6675搭建简易温度监控系统

从零搭建热电偶温度监控系统&#xff1a;STM32F103C8T6与MAX6675实战指南 在工业测量和创客项目中&#xff0c;温度监控是最基础却至关重要的环节。想象一下&#xff0c;当你需要精确控制3D打印机的热床温度、监测烘焙设备的加热曲线&#xff0c;或是记录温室大棚的环境变化时&…...

Java并发面经(一)

1.Wait和Sleep的区别sleep () 是 Thread 类的静态方法&#xff0c;让当前线程休眠指定时间&#xff0c;不会释放持有的锁&#xff1b;wait () 是 Object 类的方法&#xff0c;会让当前线程释放锁&#xff0c;并进入等待队列&#xff0c;直到被 notify ()/notifyAll () 唤醒或超…...

async-http-client原生镜像大小优化:GraalVM裁剪终极指南 [特殊字符]

async-http-client原生镜像大小优化&#xff1a;GraalVM裁剪终极指南 &#x1f680; 【免费下载链接】async-http-client Asynchronous Http and WebSocket Client library for Java 项目地址: https://gitcode.com/gh_mirrors/as/async-http-client 在当今云原生和微服…...

终极指南:如何用billboard.js实现机器学习预测结果的可视化展示

终极指南&#xff1a;如何用billboard.js实现机器学习预测结果的可视化展示 【免费下载链接】billboard.js &#x1f4ca; Re-usable, easy interface JavaScript chart library based on D3.js 项目地址: https://gitcode.com/gh_mirrors/bi/billboard.js billboard.j…...

OpenClaw语音交互方案:nanobot镜像对接语音输入输出

OpenClaw语音交互方案&#xff1a;nanobot镜像对接语音输入输出 1. 为什么需要语音交互能力 作为一个长期使用OpenClaw的技术爱好者&#xff0c;我一直在思考如何让这个强大的自动化工具更加"人性化"。传统的命令行和文本交互方式虽然高效&#xff0c;但对于不擅长…...

公开信息整理|2026年3月26日:科学进展、词元活动、食品安全、护理保险与部分国际动态速览

&#x1f525;个人主页&#xff1a;杨利杰YJlio❄️个人专栏&#xff1a;《Sysinternals实战教程》《Windows PowerShell 实战》《WINDOWS教程》《IOS教程》《微信助手》《锤子助手》 《Python》 《Kali Linux》 《那些年未解决的Windows疑难杂症》&#x1f31f; 让复杂的事情更…...

ARM A53上跑通1080P实时EIS防抖?手把手教你优化特征点与透视变换(附代码思路)

ARM A53实战&#xff1a;1080P实时EIS防抖的7个关键优化策略 当行车记录仪的镜头在颠簸路面剧烈晃动&#xff0c;或是运动相机在冲浪时被海浪拍打&#xff0c;画面稳定性的价值就凸显出来。传统光学防抖受限于物理结构&#xff0c;而电子防抖(EIS)通过算法补偿成为嵌入式设备的…...