c++类和对象新手保姆级上手教学(中)

news2025/1/16 16:52:14

前言:

  类和对象中篇,这里讲到的前4个默认成员函数,是类和对象中的重难点,许多资料上的讲法都非常抽象,难以理解,所以我作出这篇总结,分享学习经验,以便日后复习。

目录

6个默认成员函数:

构造函数:

1.概念:

2.用法:

3.特性:

 析构函数:

1.概念:

2.用法:

 3.特性:

4.析构调用顺序练习:

拷贝构造函数:

1.概念:

2.用法:

3.特性:

运算符重载:

用法:

赋值重载:

前置++和后置++重载:

 取地址重载(不重要):

const成员函数:

 


6个默认成员函数:

什么是默认成员函数?

默认成员函数就是你不写编译器自己会自动生成的成员函数

前四个默认成员函数较为重要,后两个很少会自己实现,除非常特殊的情况下,基本上不会自己实现。

构造函数:

1.概念:

  想必大家再用c语言实现栈,链表等数据结构的时候,都会先写一个初始化函数,来初始化我们的数据,但在使用中有时往往会忘记初始化,所以C++就产生了构造函数。

构造函数的作用就是进行初始化

2.用法:

  那构造函数具体是怎样来使用的呢?举一个简单的案例,一个日期类的构造函数如下:

3.特性:

  构造函数的函数名和类名相同。

  无返回值。

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

  构造函数支持重载。

  建议写成全缺省。 

  一个类必须要有默认构造函数,如果你没有写,编译器会自己生成默认构造函数,但编译器默认生成的构造函数内置类型不作处理,自定义类型去调用它的默认构造函数。但在C++11中委员会可能认为对内置类型不作处理显得很呆,所以对这个语法打补丁,支持在声明处给缺省值:

这样编译器默认生成的构造函数就会对内置类型进行处理。 

  但大多数情况下,构造函数都是需要我们自己去实现的。

无参构造函数,全缺省构造函数,编译器默认生成的构造函数,都可以称为默认构造函数,但一个类默认构造函数只能有一个,建议写成全缺省,避免歧义。

 析构函数:

1.概念:

  如果说构造函数的功能时初始化,那么析构函数就像它的死对头:

析构函数负责清理资源的工作,防止内存泄漏。

 还是一样,我们在使用栈,链表等数据结构时最容易忘的就是用完后忘记清理空间,这将导致严重的后果,也就是内存泄漏,而C++中的析构函数可以有效解决这个问题。

2.用法:

由于我这个日期类不涉及动态资源,所以析构函数不必自己实现,但仍会调用:

 3.特性:

 函数名 = ~类名

 无返回值

 一个类只能有一个析构函数,如果不写编译器自己生成

 析构函数不能重载

 对象生命周期结束时,编译器自动调用析构函数

 对于编译器自己生成的析构函数,同样是内置类型不作处理,自定义类型调用它自己的析构函数。

4.析构调用顺序练习:

对于析构函数,其实头疼的是它的多个函数析构时的调用顺序,这里给大家一个公式,大家以后套公式即可:

局部对象(后定义先析构)->局部静态(后定义先析构)->全局对象(后定义先析构)

下面由浅入深来练习一下: 

练习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 Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}
	~Date()
	{
		cout << "调用析构" << _year << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(1);
	Date d2(2);
	Date d3(3);
	return 0;
}

因为他们都是局部变量,遵循后定义先析构,所以:

练习2:

#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 Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}
	~Date()
	{
		cout << "调用析构" << _year << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
Date d1(1);
Date d2(2);
Date d3(3);
int main()
{
	//Date d1(1);
	//Date d2(2);
	//Date d3(3);
	return 0;
}

 现在他们都变为全局变量,仍遵循后定义先析构:

练习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;
	}
	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}
	~Date()
	{
		cout << "调用析构" << _year << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(1);
	static Date d2(2);
	static Date d3(3);
	Date d4(4);
	return 0;
}

 现在,d2变成局部静态,根据公式,先局部对象再局部静态,内部仍然按照后定义先析构:

练习4:

#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 Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}
	~Date()
	{
		cout << "调用析构" << _year << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
Date d5(5);
static Date d6(6);
Date d7(7);
static Date d8(8);
int main()
{
	Date d1(1);
	static Date d2(2);
	static Date d3(3);
	Date d4(4);
	return 0;
}

 先局部对象,再局部静态,最后全局,不管全局对象是否为静态,都遵循后定义先析构:

拷贝构造函数:

1.概念:

 在使用C++中,我们往往会需要将一个类拷贝到另一个相同类型的类中,而拷贝构造函数的作用就是:将该类拷贝到同类型的类中。

2.用法:

为了更严谨,也可以在此处加上const:

 

3.特性:

 函数名和类名相同

 无返回值

 形参部分传引用

 拷贝构造函数也是构造函数

 如果我们不写,编译器会默认生成,默认生成的拷贝构造函数对内置类型成员按内存存储按字节序拷贝,也就是浅拷贝,对自定义成员调用它的拷贝构造。

为什么形参部分必须传引用呢?

因为不传引用可能会引发无穷递归,看下面这个例子:

此时像上图一样使用拷贝构造函数,如果我们的拷贝构造函数是传值:

 

那就需要先调用拷贝构造,调用到拷贝构造时,因为是传值,所以需要将d1先拷贝到形参d,而将d1拷贝到形参d,就又需要调用新的拷贝构造,而新的拷贝构造又是传值,所以就这样一直递归下去,无穷无尽。

编译器默认生成的拷贝构造会拷贝内置类型,那么是不是意味着我们不需要自己实现拷贝构造?

不!!!

编译器默认生成的拷贝构造只能进行浅拷贝。

当我们有一个栈,里面有一个指针,指向了一片空间,当我们还是浅拷贝,用编译器默认生成的拷贝构造函数的话,它就会原原本本的将指针的拷贝到新的指针中,这就导致这篇空间有两个指针指向它,而不是像我们预想的一样,拷贝一块新空间,所以当要进行深拷贝时,我们需要自己来写拷贝构造函数 

所以写拷贝构造时,浅拷贝不需要写,只有有动态资源开辟的,才需要自己写拷贝构造。

运算符重载:

关键字:operator

用法:

将函数名改成operator加需要重载的运算符

在c语言中,对于内置类型我们可以直接用<  >  =  +  -  等符号进行运算,但如果我们要对自定义类型进行运算的话,就需要自己写函数来实现。

如果用运算符重载的话,将大大提高代码的可读性,比如我们实现一个判断两个日期类是否相同,重载==:

重载成成员函数:

重载成全局函数: 

 用法:

显而易见,第三种方法最实用,大大提高了代码的可读性 。

赋值重载:

这里的内容涉及的运算符重载,建议先跳到运算符重载,再来学习这段。

区分拷贝和赋值:

众所周知自定义类型是不能直接用等号连接进行赋值的,那么就需要进行运算符重载;

赋值重载和拷贝构造类似,但赋值重载是支持连续赋值的:

注意赋值重载只能重载成成员函数。 

前置++和后置++重载:

前置++和后置++这两个运算符一模一样,但是作用效果却不同,为了不产生歧义,该如何进行重载呢?

前置++:

用法:

后置++: 

用法 :

可见为了和前置++区分开来,后置++强制增加了一个形参int 来区分。 

 取地址重载(不重要):

主要是对对象进行取地址操作,编译器自己生成的已经完全够用,没有必要再自己写,除非有特殊需求:

const成员函数:

如果我们希望某个成员函数不能对成员变量进行修改时,我们可以进行const修饰:

用法: 

我们可以对不用对成员变量进行修改的成员函数进行const修饰,增加代码的严谨性。如果const修饰的成员函数对成员变量进行了修改,编译器会报错:

C++类和对象中篇到此结束,这篇是最难也是最重要的一篇,下篇我会陆续更新进行收尾。 

 

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

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

相关文章

基于uniapp微信小程序的汽车租赁预约系统

随着现代汽车租赁管理的快速发展&#xff0c;可以说汽车租赁管理已经逐渐成为现代汽车租赁管理过程中最为重要的部分之一。但是一直以来我国传统的汽车租赁管理并没有建立一套完善的行之有效的汽车租赁管理系统&#xff0c;传统的汽车租赁管理已经无法适应高速发展&#xff0c;…

【lesson59】线程池问题解答和读者写者问题

文章目录 线程池问题解答什么是单例模式什么是设计模式单例模式的特点饿汉和懒汉模式的理解STL中的容器是否是线程安全的?智能指针是否是线程安全的&#xff1f;其他常见的各种锁 读者写者问题 线程池问题解答 什么是单例模式 单例模式是一种 “经典的, 常用的, 常考的” 设…

MySQL多实例部署:从概念到实操的全面指南

目录 MySQL多实例管理 单实例 什么是多实例 多实例的好处 多实例的弊端 MySQL多实例用在哪些场景 资金紧张的公司 用户并发访问量不大的业务 大型网站也有用多实例 部署MySQL多实例 rpm和源码的优缺点 二进制方式安装mysql 准备二进制mysql运行所需的环境 准备多…

ENG-2 AM,绿色钠离子探针,能够与常用的显微镜和光谱仪兼容

文章关键词&#xff1a;ENG-2 AM&#xff0c;钠离子荧光探针ENG-2&#xff0c;绿色钠离子探针 一、基本信息 产品简介&#xff1a;Enhanced NaTrium Green-2 AM (ENG-2 AM) 是一种新型的钠离子&#xff08;Na&#xff09;荧光探针&#xff0c;它作为 Asante NaTrium Green-2 …

[Bug解决] Invalid bound statement (not found)出现原因和解决方法

1、问题描述 在写了一个很普通的查询语句之后&#xff0c;出现了下面的报错信息 org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.xxx.oauth.mapper.WxVisitorQrBeanMapper.selectByComIdAndEmpId at org.apache.ibatis.binding.Mappe…

力扣日记2.20-【回溯算法篇】491. 非递减子序列

力扣日记&#xff1a;【回溯算法篇】491. 非递减子序列 日期&#xff1a;2023.2.20 参考&#xff1a;代码随想录、力扣 ps&#xff1a;放了个寒假&#xff0c;日记又搁置了三星期……&#xff08;下跪忏悔&#xff09; 491. 非递减子序列 题目描述 难度&#xff1a;中等 给你一…

《Solidity 简易速速上手小册》第3章:Solidity 语法基础(2024 最新版)

文章目录 3.1 变量和类型3.1.1 基础知识解析详细解析变量类型深入数据类型理解变量可见性 3.1.2 重点案例&#xff1a;创建一个简单的存储合约案例 Demo&#xff1a;编写一个简单的数字存储合约案例代码&#xff1a;SimpleStorage.sol在 Remix 中进行交互&#xff1a;拓展操作&…

【python】linux系统python报错“ssl module in Python is not available”

一、问题现象 1.1 执行pip命令报错 pip安装时遇到openssl问题&#xff0c;没办法安装第三方库 “WARNING: pip is configured with locations that require TLS/SSL, however the ssl module in Python is not available. ” 1.2 导入import ssl 报错 直接执行python&…

算法面试八股文『 模型详解篇 』

说在前面 这是本系列的第二篇博客&#xff0c;主要是整理了一些经典模型的原理和结构&#xff0c;面试有时候也会问到这些模型的细节&#xff0c;因此都是需要十分熟悉的。光看原理还不够&#xff0c;最好是能用代码试着复现&#xff0c;可以看看李沐老师深度学习的教材&#…

AT24C02(I2C总线)通信的学习

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、存储器介绍二、AT24C02芯片二、I2C总线I2C电路规范I2C时序结构I2C数据帧AT24C02数据帧 总结 前言 学习AT24C02(I2C总线)芯片 一、存储器介绍 RAM&#xf…

PostgreSQL使用session_exec和file_fdw实现失败次数锁定用户策略

使用session_exec 、file_fdw以及自定义函数实现该功能。 缺陷&#xff1a;实测发现锁用户后&#xff0c;进去解锁特定用户。只能允许一次登陆&#xff0c;应该再次登陆的时候&#xff0c;触发函数&#xff0c;把之前的日志里的错误登陆的信息也计算到登录次数里了。而且foreig…

VsCode指定插件安装目录

VsCode指定插件安装目录 VsCode安装的默认目录是在用户目录(%HomePath%)下的.vscode文件夹下的extensions目录下&#xff0c;随着安装插件越来越多会占用大量C盘空间。 指定VsCode的插件目录 Vscode安装目录&#xff1a; D:\Microsoft VS Code\Code.exeVscode插件安装目录&a…

MyBatis数据库查询

文章目录 什么是MyBatisMyBatis程序的创建MyBatis实现数据库查询传参查询插入实现添加操作获取自增ID删除实现修改实现#{}和${}SQL注入 like查询 resultMap和resultType多表查询 对于普遍的后端开发而言&#xff0c;其程序主要包含了后端主程序和数据库两个部分&#xff0c;用户…

【Java】eclipse安装JDBC连接MySQL数据库教程

1.下载JDBC 首先在官网中下载JDBC&#xff0c;下载地址&#xff1a;MySQL :: MySQL Connectors 如果无法进入官网可以点击这里下载&#xff1a;https://download.csdn.net/download/weixin_47040861/88855729 进入官网后找到Develop by MySQL一栏&#xff0c;在该栏下找到JDB…

代码随想录算法训练营DAY20 | 二叉树 (8)

一、LeetCode 701 二叉搜索树中的插入操作 题目链接&#xff1a; 701.二叉搜索树中的插入操作https://leetcode.cn/problems/insert-into-a-binary-search-tree/description/ 思路&#xff1a;见缝插针罢辽。 class Solution {public TreeNode insertIntoBST(TreeNode root, i…

数组的左旋和右旋算法

public class Test09 {public static void main(String[] args) {//右旋 数组逆序遍历&#xff0c;将尾部元素&#xff0c;不断交换至头部int[] arr {1,2,3,4,5,6,7,8};for(int i arr.length-1;i>0;i--) { //遍历一次arr[i] arr[i] ^ arr[i-1];arr[i-1] arr[i] ^ arr[i…

【EI会议征稿通知】第九届电子技术和信息科学国际学术会议(ICETIS 2024)

第九届电子技术和信息科学国际学术会议&#xff08;ICETIS 2024&#xff09; The 9th International Conference on Electronic Technology and Information Science&#xff08;ICETIS 2024&#xff09; ICETIS会议始于2016年&#xff0c;先后吸引众多来自国内外高等院校、科…

如何看待Java是一门半编译半解释型的语言(企业真题)

如何看待Java是一门半编译半解释型的语言 解答&#xff1a;可能是解释执行&#xff0c;可能是编译执行

用户空间与内核通信(二)

文章&#xff1a;用户空间与内核通信&#xff08;一&#xff09;介绍了系统调用&#xff08;System Call&#xff09;&#xff0c;内核模块参数和sysfs&#xff0c;sysctl函数方式进行用户空间和内核空间的访问。本章节我将介绍使用netlink套接字和proc文件系统实现用户空间对内…

《白话C++》第10章 STL和boost,Page101 10.4.6 std::weak_ptr

2.基本功能 “柔弱的”weak_ptr专门用来解决上述设计中必须面对的循环指向问题。 weak_ptr并不是真正的智能指针&#xff0c;它必须依附于shared_ptr存在。对应前面的C1、C2&#xff0c;我们写一个弱引用版本的C3和C4的例子&#xff1a; struct C4; struct C3 {~C3(){cout…