C++入门之类和对象(中)

C++入门之类和对象(中)

文章目录

  • C++入门之类和对象(中)
    • 1. 类的6个默认对象
    • 2. 构造函数
      • 2.1 概念
      • 2.2 特性
      • 2.3 补丁
    • 3. 析构函数
      • 3.1 概念
      • 3.2 特性
      • 3.3 总结
    • 4. 拷贝构造函数
      • 4.1 概念
      • 4.2 特性
      • 4.3 总结

1. 类的6个默认对象

如果一个类中什么都没有,那么这个类就是一个空类。但是,任何类如果什么都不写的话,编译器会自动生成6个默认成员函数

默认成员函数:用户没有显式实现(用户没有写),编译器自动生成的成员函数被称为默认成员函数

class Data{};

在这里插入图片描述

2. 构造函数

2.1 概念

假设有以下类:

#include <iostream>
using namespace std;
class Date
{
public:void Init(int year = 2024, int month = 4, int day = 15){_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();d1.Print();Date d2;d2.Init(2024, 5, 1);d2.Print();return 0;
}

上述类中是使用Init函数对类进行初始化,Init使用全缺省参数,如果没有传值的话,使用缺省值初始化,但是对于这这种类,就算不初始化也不会有什么问题,但是对于顺序表,链表等,如果不初始化就会报错,往往我们会容易忘记调用初始化,这时候,构造函数就派上用场了

构造函数是一种特殊的函数,名字与类名相同,没有返回值(在默认成员函数中,没有返回值指的都是不写),在创建类对象时由编译器自动调用,保证每个成员都有一个初始值,并且在类对象整个生命周期只会调用一次

2.2 特性

构造函数是一种特殊的函数,构造函数并不是用于开辟空间创建对象,而是为对象进行初始化

特征

  1. 函数名与类名相同
  2. 函数没有返回值(不写返回值)
  3. 对象实例化时编译器会自动调用
  4. 构造函数可以重载(可以根据需求写多个初始化方式)
  5. 如果类中没有显式定义构造函数(没有写),编译器就会自动生成一个无参的构造函数,反之,编译器则不会生成
  6. 由编译器生成的无参构造函数,不会对类中的内置类型(int char等等)进行处理,但是对调用类中自定类型(class struct union等等)的构造函数,如果类中自定类型还是没有则也不处理
    C++中没有规定对自定类型(class struct union等等)初始化成0或者其他,取决于编译器的实现
  7. 无参构造函数全缺省的构造函数由编译器自动生成构造函数都可以被称为默认参构造函数,但是默认参构造函数只能存在一个

示例1:

#include <iostream>
using namespace std;
class Date
{
public://Date(int year, int month, int day) (这种写法会报错,这种不是默认的构造函数)Date(int year = 2024, int month = 4, int day = 15){_year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year;int _month;int _day;
};int main()
{Date d1;//调用全缺省的构造函数(2024-4-15)d1.Print();return 0;
}

示例2:

#include <iostream>
using namespace std;
class Time
{
private:int _hour;int _minute;int _second;
};
class Date
{
public:void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year;int _month;int _day;Time a;
};int main()
{Date d1;d1.Print();return 0;
}

在这里插入图片描述

示例3:

#include <iostream>
using namespace std;
class Date
{
public:Date(){}Date(int year = 1, int month = 1, int day = 1){_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.Print();return 0;
}

存在多个构造函数,报错

2.3 补丁

由于不对内置类型进行初始化,所以在C++ 11中,打了一个补丁,允许内置成员在声明时可以给一个默认值

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

用声明时的默认值初始化(2024-4-15)

总结:
一般情况下,构造函数都要由我们自己实现,少部分情况下可以不用实现(如果类中只有自定类型,而这个自定类型内部存在构造函数),例如:MyQueue

3. 析构函数

3.1 概念

析构函数是与构造函数相反的一种特殊函数,析构函数不是对对象进行销毁,局部变量的销毁是由编译器处理的,而是析构函数是对对象中资源的清理,且会在对象销毁时自动调用

3.2 特性

  1. 在类名前面加上~
  2. 无参数无返回值(不写返回值)
  3. 一个类只有一个析构函数,如果没有显式定义(没有写),则编译器会自动生成默认析构函数(由于没有参数,析构函数不能重载)
  4. 在对象生命周期结束时,编译器会自动调用析构函数
  5. 与构造函数相似的是,析构函数不会对内置类型进行处理,对自定类型则是调用其析构函数

示例:

#include <iostream>
using namespace std;
class Stack
{
public:Stack(int n = 4){cout << "Stack()" << endl;int* tmp = (int*)malloc(sizeof(int) * n);if (nullptr == tmp){perror("malloc fail");return;}_arr = tmp;_capacity = n;_size = 0;}void Push(int x){//扩容_arr[_size] = x;_size++;}~Stack(){cout << "~Stack()" << endl; //方便查看if (_arr) //防止被多次销毁,加个判断{free(_arr);_arr = nullptr;_capacity = 0;_size = 0;}}
private:int* _arr;int _size;int _capacity;
};
int main()
{Stack s;s.Push(1);s.Push(2);s.Push(3);s.~Stack();return 0;
}

在这里插入图片描述

析构函数也是可以显式调用的

3.3 总结

  1. 在没有需要资源清理的时候可以不写析构函数,
    a. 如Date类,没有需要清理的内置类型
    b.没有需要清理的内置类型,剩下的其他自定类型中存在析构函数,如MyQueue,也不需要写析构函数
    2.有资源清理就要写析构函数,如Stack,List

4. 拷贝构造函数

4.1 概念

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

4.2 特性

  1. 是构造函数的一种重载形式(函数名与类型一致)
  2. 拷贝构造函数的参数只能有一个,且得是类类型对象的引用,否则在使用拷贝构造函数会直接报错(引发无穷递归调用)
  3. 如果没有显式定义,编译器会自动生成默认的拷贝构造函数,默认的拷贝构造函数会对内置类型进行处理,按内存存储按字节序完成拷贝,也被称为浅拷贝或者值拷贝

示例1:

#include <iostream>
using namespace std;
class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}void Init(int year = 2024, int month = 4, int day = 15){_year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year;int _month;int _day;
};int main()
{Date d1(2024,4,15);Date d2 = d1; //与下面创建对象d3是等价的,两种写法d2.Print();Date d3(d1);d3.Print();return 0;
}

示例2:

#include <iostream>
using namespace std;
class Stack
{
public:Stack(int n = 4){cout << "Stack()" << endl;int* tmp = (int*)malloc(sizeof(int) * n);if (nullptr == tmp){perror("malloc fail");return;}_arr = tmp;_capacity = n;_size = 0;}void Push(int x){//扩容_arr[_size] = x;_size++;}~Stack(){cout << "~Stack()" << endl;if (_arr){free(_arr);_arr = nullptr;_capacity = 0;_size = 0;}}
private:int* _arr;int _size;int _capacity;
};
int main()
{Stack s1;s1.Push(1);s1.Push(2);s1.Push(3);Stack s2 = s1;return 0;
}

代码运行结果:
报错

  编译器生成的默认拷贝构造是不够用,在上述代码中,s2对象使用s1对象的拷贝,由于是浅拷贝,会将s1中的内容原封不动的拷贝给s2,因此s1和s2调用的是同一块空间,在调用析构函数时,s1将空间释放了,但是s2中存放的还是s1的空间,因为还会再释放一次,一块内存空间的多次释放,会造成程序奔溃。同时在对任意一个栈中push数据的时候,另一个栈中的size是不会加的,但是共用的是同一块空间,数据丢失等等问题

示例3:错误写法

#include <iostream>
using namespace std;
class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}Date(Date d) //错误写法 会引发无穷递归{_year = d._year;_month = d._month;_day = d._day;}
private:int _year;int _month;int _day;
};Date Func(Date d)
{Date tmp(d);return tmp;
}int main()
{Date d1(2024, 4, 15);Func(d1);return 0;
}

在返回一个局部变量时,由于局部变量出作用域就销毁了,所以会将局部变量拷贝给一个临时变量,在给拷贝给临时变量时,又会调用拷贝构造函数,在调用拷贝构造函数时,又会将返回值拷贝给一个临时变量,造成无穷递归

4.3 总结

  1. 在类中,如果没有涉及需要资源管理的内置类型,是可以不写拷贝构造函数的,编译器自动生成的浅拷贝就够用,但是一旦涉及,就需要自己实现拷贝构造函数了
  2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用

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

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

相关文章

什么是代理IP?如何正确使用代理IP?

代理IP&#xff08;Proxy IP&#xff09;是一种网络技术&#xff0c;它允许用户通过一个中介服务器&#xff08;即代理服务器&#xff09;来访问互联网。具体来说&#xff0c;代理IP隐藏了用户的真实IP地址&#xff0c;使用第三方的IP地址进行网络访问。当用户发起网络请求时&a…

CAD小软件diy-读柴油机壳体装配图

读取一个柴油机壳体dxf图纸&#xff0c;一般这种装配体轮廓曲线都是用直线和圆弧拟合的&#xff0c;全部都是显示的白色实现&#xff0c;发现有线段间隙&#xff0c;拖动线段补上间隙。 这个测试放在蓝奏云上面 https://wwf.lanzout.com/ip1Xx1vvhbkh

tcp bbr pacing 的对与错

前面提到 pacing 替代 burst 是大势所趋&#xff0c;核心原因就是摩尔定律逐渐失效&#xff0c;主机带宽追平交换带宽&#xff0c;交换机不再能轻易吸收掉主机突发&#xff0c;且随着视频类流量激增&#xff0c;又不能以大 buffer 做带宽后备。因此&#xff0c;主机必须 pacing…

A-1:树状数组

A-1:树状数组 1.介绍Q1:树状数组解决什么问题&#xff1f;Q2:树状数组的使用1.前置知识&#xff1a;lowbit(x)2.单点修改3.求[1,n]的和4.区间查询5.hh Q3:树状数组是否优化了Q4:上图上例子解释上面说的东西(Important) 2.习题练习 1.介绍 树状数组是一个比较难以理解的高级数据…

C语言---单链表(二)

文章目录 前言1.准备工作2,打印链表、创建新的节点、销毁链表2.1.打印链表2.2.创建节点2.3.销毁链表 3.尾插、头插、尾删、头删3.1.尾插3.2.头插3.3.尾删3.4.头删 4.在特殊位置之前、之后插入、删除以及查找节点4.1.查找节点4.2.在指定位置之前插入4.3.在指定位置之后插入数组4…

亚信安全入选中国数据安全市场图谱

近日&#xff0c;全球领先的IT市场研究和咨询公司IDC发布了《IDC Market Glance&#xff1a;中国数据安全市场图谱&#xff0c;2024》报告&#xff08;以下简称“报告”&#xff09;&#xff0c;报告展示了中国数据安全市场的构成和格局&#xff0c;遴选出不同细分市场领域的主…

C语言中的结构体:从定义到传递

前言 结构体是C语言中一种重要的数据类型&#xff0c;它允许我们将不同类型的数据组合成一个整体&#xff0c;并以自定义的方式进行操作。通过结构体&#xff0c;我们可以更加灵活地管理和处理复杂的数据结构&#xff0c;从而提高程序的可读性和可维护性。本篇博客将从结构体的…

jetcache fastjson 泛型复杂对象JSON序列 ,反序列化

Jetcache fastjson 泛型复杂对象JSON序列 ,反序列化 默认的FastJson2 序列化存在问题增强FastJson 支持Encode 编码器Decode 解码器 默认的FastJson2 序列化存在问题 默认的序列化不能转换List 中的泛型数据类型, 从缓存拿取的list集合对象数据全部都转换成了JSONObject 增强F…

nginx--Nginx转发真实的IP

Nginx转发真实的IP 前言给nginx.conf 设置proxy_set_headerjava 程序里获取 前言 在使用nginx的时候可能会遇到判断是不是本机在做操作&#xff0c;这样的话web端我们是可以通过ip和端口进行远程连接的这样的话我们就需要从后端获取到真实ip来判断是不是指定的机器了&#xff…

Linux 序列化、反序列化、实现网络版计算器

目录 一、序列化与反序列化 1、序列化&#xff08;Serialization&#xff09; 2、反序列化&#xff08;Deserialization&#xff09; 3、Linux环境中的应用实例 二、实现网络版计算器 Sock.hpp TcpServer.hpp Jsoncpp库 Protocol.hpp 类 Request 类 Response 辅助函…

稳压二极管仿真实验

稳压二极管仿真实验 1、稳压管稳压实验 用Multisim搭建如下的仿真电路图&#xff0c;选用5.1V的稳压管&#xff0c;12V的直流电源&#xff0c;开启仿真后&#xff0c;12V电压将稳压管击穿&#xff0c;稳压管将两端的电压稳压到5.07V&#xff0c;该电压与限流电阻R1的阻值有关…

跟着Carl大佬学leetcode之977 有序数组的平方

来点强调&#xff0c;刷题是按照代码随想录的顺序进行的&#xff0c;链接如下https://www.programmercarl.com/本系列是记录一些刷题心得和学习过程&#xff0c;就看到题目自己先上手试试&#xff0c;然后看程序员Carl大佬的解释&#xff0c;自己再敲一遍修修补补&#xff0c;练…

msyql中SQL 错误 [1118] [42000]: Row size too large (> 8126)

场景&#xff1a; CREATE TABLE test-qd.eqtree (INSERT INTO test.eqtree (idocid VARCHAR(50) NULL,sfcode VARCHAR(50) NULL,sfname VARCHAR(50) NULL,sfengname VARCHAR(50) NULL,…… ) ENGINEInnoDB DEFAULT CHARSETutf8 COLLATEutf8_general_ci;或 alter table eqtre…

Token 在 LLM

大语言模型不能理解原始文本,所以需要把原始文本转换成大语言模型可以理解的数字表示形式,经过大模型处理以后,需要将该数字表示形式转换为人可以理解的文本。 原始文本到 token 原始文本转换为token序列的过程通常是在LLM的预处理阶段完成的。 在大型语言模型(LLM)中,tok…

力扣:LCR 022. 环形链表 II

力扣&#xff1a;LCR 022. 环形链表 II 给定一个链表&#xff0c;返回链表开始入环的第一个节点。 从链表的头节点开始沿着 next 指针进入环的第一个节点为环的入口节点。如果链表无环&#xff0c;则返回 null。 为了表示给定链表中的环&#xff0c;我们使用整数 pos 来表示链…

学习java时候的笔记(十九)

正则表达式 作用: 校验字符串是否满足规则在一段文本中查找满足要求的内容 字符类(只匹配一个字符) 说明[abc]只能是a,b或c[^abc]除了a,b,c之外的任何字符[a-zA-Z]a 到 z, A 到 Z(范围)[a-d[m-p]]a 到 d, 或 m 到 p[a - z && [def]]a 到 z和def的交集。为: d, e, f…

【树莓派学习】系统烧录及VNC连接、文件传输

【树莓派学习】系统烧录及VNC连接、文件传输 Raspberry Pi is a series of small single-board computers (SBCs) developed in the United Kingdom by the Raspberry Pi Foundation in association with Broadcom. Since 2013, Raspberry Pi devices have been developed and…

Ubuntu20.4版本安装ROS教程

一、配置源 安装成功的Ubuntu系统自带的工具下载速度慢&#xff0c;不太好用&#xff0c;所以我们可以使用国内稳定高速且免费的镜像网站。 清华源&#xff1a;https://pypi.tuna.tsinghua.edu.cn/simple/ 阿里云&#xff1a;https://mirrors.aliyun.com/pypi/simple 中科大&…

启动 UE4编辑器报 加载 Plugin 失败

启动 UE4编辑器报 加载 Plugin 失败&#xff0c;报如下错误&#xff1a; Plugin ‘SteamVR’ failer to load because module ‘SteamVR’ could not be found. Please ensure the plugin is properly installed, otherwise consider disabling the plugin for this project. …

TorchEEG文档_学习笔记1【代码详解】

文章目录 一、用户文档1.安装Pytorch2.安装TorchEEG3.安装与图算法的插件 二、教程1.使用TorchEEG完成深度学习工作流程2datasets模块3.transforms模块4.models模块5.trainer模块6.使用Vanilla PyTorch训练模型 一、用户文档 1.安装Pytorch TorchEEG依赖于PyTorch,根据系统、…