【小梦C嘎嘎——启航篇】类和对象(中篇)

news2024/12/28 4:51:07

【小梦C嘎嘎——启航篇】类和对象(中篇)😎

  • 前言🙌
    • 类的6个默认成员函数
      • 构造函数
      • 析构函数
      • 拷贝构造函数
        • 拷贝构造函数的特性有哪些?
        • 既然编译器可以自动生成一个拷贝构造函数,为什么我们还要自己设计实现呢???
        • 拷贝构造函数典型调用场景有哪些呢???
      • 运算符重载
        • 运算符重载需要注意的地方
      • 赋值运算符重载
        • 赋值运算符重载函数有哪些特性???
        • 为什么赋值重载函数只能重载成类成员函数不能重载成全局函数呢???
        • 既然编译器可以自动生成一个赋值重载函数了,为什么我们还要自己设计实现呢???
      • 前置++和后置++重载
        • 前置++:返回+1之后的结果
        • 后置++:
      • const 修饰的成员
        • const对象可以调用非const成员函数吗?非const对象可以调用const成员函数吗?const成员函数内可以调用其它的非const成员函数吗?非const成员函数内可以调用其它的const成员函数吗?
      • 取地址及const取地址操作符重载
  • 总结撒花💞

追梦之旅,你我同行

   
😎博客昵称:博客小梦
😊最喜欢的座右铭:全神贯注的上吧!!!
😊作者简介:一名热爱C/C++,算法等技术、喜爱运动、热爱K歌、敢于追梦的小博主!

😘博主小留言:哈喽!😄各位CSDN的uu们,我是你的博客好友小梦,希望我的文章可以给您带来一定的帮助,话不多说,文章推上!欢迎大家在评论区唠嗑指正,觉得好的话别忘了一键三连哦!😘
在这里插入图片描述

前言🙌

    哈喽各位友友们😊,我今天又学到了很多有趣的知识,现在迫不及待的想和大家分享一下!😘我仅已此文,分享有关 C++ 类和对象的相关知识 ~ 都是精华内容,可不要错过哟!!!😍😍😍

类的6个默认成员函数

构造函数

  • 构造函数是用来对对象初始化的,并非是为对象开辟空间的。
  • 构造函数的函数名与类名相同。
  • 无返回值类型,不用写void
  • 一个类中可以有多个构造函数,也就是构造函数是可以实现重载的。
  • 在定义对象时,会自动调用构造函数,对对象进行初始化操作。
  • 构造函数是类的默认成员函数,如果自己没有写,编译器会默认生成一个无参的构造函数。
  • 默认构造函数:无参的构造函数、全缺省的构造函数、自己没写编译器自动生成的构造函数。在一个类中,有且只有一个默认构造函数。当有多个时,会出现调用冲突。
  • 当要调用无参的构造函数时,定义对象时不要加(),例如Data d(),这样是错误的。这样编译器区分不清它是函数声明还是调用构造函数,产生二义性了。

析构函数

  • 析构函数是用来进行对对象资源的清理工作,而不是用来销毁对象,销毁对象是程序结束系统自动销毁回收空间的。
  • 析构函数的函数名与类名相同,前面加一个~。
  • 无返回值也无参数。
  • 一个类中只能有一个析构函数,不能实现重载。
  • 在程序结束时,编译器会自动先调用析构函数。
  • 构造函数是类的默认成员函数,如果自己没有写,编译器会默认生成一个无参的构造函数。

拷贝构造函数

什么是拷贝构造函数?顾名思义,就是完成对象的之间的拷贝。

拷贝构造函数的特性有哪些?

这里,我对拷贝构造函数总结为以下几点特性:

  • 拷贝构造函数是一种特殊的函数。

  • 拷贝构造函数其实就是构造函数的一个重载。

  • 如果没有显示的实现拷贝构造函数,编译器会自动生成默认拷贝构造函数供程序使用。

  • 一个已经存在的对象拷贝给一个还不存在的对象时,编译器会自动调用拷贝构造函数。

  • 一般在传值传参和传值返回中,会调用拷贝构造函数。

  • 拷贝构造函数函数列表中,有且只有一个参数,一般加上const修饰,且必须是本类类型对象的引用,如果不是引用的话会导致无限递归的问题。

既然编译器可以自动生成一个拷贝构造函数,为什么我们还要自己设计实现呢???

我的理解是:编译器生成的默认构造函数只能完成浅拷贝的工作而不能实现深拷贝,而我们在实际开发过程中有些场景是需要深拷贝才能够解决问题的。由于在C++中,默认拷贝构造函数对内置数据类型只完成值拷贝(浅拷贝),对于自定义类型会调用它们的拷贝构造函数。如果,我们实现的类只有内置类型成员变量,也就是说不涉及申请其他资源的,可以只使用编译器提供的默认拷贝构造函数就可以满足我们的需求,无需自己实现,例如Date类的实现就无需手搓拷贝构造函数。但是,如果我们需要申请其他资源,例如需要在堆区上申请空间资源等,则需要我们根据项目工程的实际场景进行手动实现拷贝构造函数,完成深拷贝。例如,我们进行栈类的实现,如果不进行深拷贝的话,会出现多次释放同一块空间资源的问题,从而报错。

拷贝构造函数典型调用场景有哪些呢???

  • 使用已经存在的对象去创建新对象
  • 函数参数类型是类类型对象
  • 函数返回值类型是类类型对象

如果一个类对象所占空间越大,拷贝所带来的消耗就越大。因此,一般在传参时,能够用引用作为参数就使用引用传参;在返回时,能够使用引用返回就不用船只返回。这样可以减少拷贝次数,提高程序的效率。

运算符重载

赋值运算符重载是运算符重载的一种。其实我们也可以不用运算符重载,写一个函数也能实现我们的需求。但是,使用运算符重载可以大大提高代码的可读性。

运算符重载需要注意的地方

  • 不能通过连接其他符号来创建新的操作符:比如operator@
  • 重载操作符必须有一个类类型参数
  • 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义
  • 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
  • .* :: sizeof ? : . 注意以上5个运算符不能重载。这个经常在笔试选择题中出现。

赋值运算符重载

赋值运算符重载函数有哪些特性???

  1. 从其函数格式可以看出,其基本格式:返回值类型 operator= (参数列表)。从提高效率来看,一般设计为引用返回即 T&。函数的参数列表中必须有一个本类类型的参数,最好实现为const T & 。赋值重砸函数有返回值的原因其实是为了连续赋值的需求。返回的是*this,以满足连续赋值的需求
  2. 一般没有自己给自己赋值的场景需求,因此在显示实现赋值重载函数时需要避开这个问题。
  3. 赋值重载函数只能重载成类的成员函数,而不能重载成全局函数。
  4. 如果没有显示的实现赋值重载函数,编译器会自动生成一个默认赋值重载函数。其对于内置类型成员变量按照完成值拷贝,对于自定义的类型的成员变量会调用它们的赋值重载函数。

为什么赋值重载函数只能重载成类成员函数不能重载成全局函数呢???

因为,如果在类中没有显示实现赋值重载函数,而是在类外实现赋值重载函数。那么编译器会在类内自动生成一个默认的赋值重载函数。而程序在调用赋值重载函数时,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数。 在《c++ Prime 第五版》这本书中也提到,如下图所示:

在这里插入图片描述

既然编译器可以自动生成一个赋值重载函数了,为什么我们还要自己设计实现呢???

这里举一个例子来理解:下面是一个栈类的简单实现。

#include<iostream>
#include<stdlib.h>
using namespace std; 

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;
	s2 = s1;
	return 0;
}

程序运行结果:

在这里插入图片描述

我们可以看到,程序执行最终崩掉了。为什么呢?接下来我画图分析一下:
在这里插入图片描述

  • s1 赋值给s2后,s1和s2的_array指向同一块空间,当s1和s2销毁的时候,都会调用析构函数对 _ array空间进行释放,就出现多次释放同一块空间的问题
  • 赋值后,s2申请的_array 指向的空间就没有人标识它的位置了,从而造成了内存泄露。

前置++和后置++重载

前置++:返回+1之后的结果

注意:this指向的对象函数结束后不会销毁,故以引用方式返回提高效率

后置++:

前置++和后置++都是一元运算符,为了让前置++与后置++形成能正确重载, C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器自动传递
注意:后置++是先使用后+1,因此需要返回+1之前的旧值,故需在实现时需要先将this保存一份,然后给this + 1。而temp是临时对象,因此只能以值的方式返回,不能返回引用

class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	
	Date& operator++()
	{
		_day += 1;
		return *this;
	}

	Date operator++(int)
	{
		Date temp(*this);
		_day += 1;
		return temp;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d;
	Date d1(2022, 1, 13);

	d = d1++;  
    d = ++d1;  
    return 0; 

}

const 修饰的成员

将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数。隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。

const对象可以调用非const成员函数吗?非const对象可以调用const成员函数吗?const成员函数内可以调用其它的非const成员函数吗?非const成员函数内可以调用其它的const成员函数吗?

这几个问题都设计了权限的问题。我们知道,只能让变量的权限平移或者缩小,不能让权限放大。因此,const对象不可以调用非const成员函数(权限放大);非const对象可以调用const成员函数(权限缩小);const成员函数内不可以调用其它的非const成员函数(权限放大);非const成员函数内可以调用其它的const成员函数(权限缩小)。

取地址及const取地址操作符重载

这两个默认成员函数一般不用重新定义 ,编译器默认会生成。

class Date
{
public:
	Date* operator&()
	{
		return this;
	}
	const Date* operator&()const
	{
		return this;
	}
private:
	int _year; // 年
	int _month; // 月
	int _day; // 日
};

这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载。

总结撒花💞

   希望大家通过阅读此文有所收获
   😘如果我写的有什么不好之处,请在文章下方给出你宝贵的意见😊。如果觉得我写的好的话请点个赞赞和关注哦~😘😘😘

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

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

相关文章

python数据分析 期末测验,python数据分析基础题库

大家好&#xff0c;小编为大家解答python数据分析选择题题目的问题。很多人还不知道python数据分析题目和答案&#xff0c;现在让我们一起来看看吧&#xff01; 自测试卷 5 一、选择题 1 &#xff0e;下面关于 RFM 模型说法正确的是&#xff08; &#xff09;。 A &#xff0e;…

微信小程序(由浅到深)

文章目录 一. 项目基本配置1. 项目组成2. 常见的配置文件解析3. app.json全局的五大配置4.单个页面中的page配置5. App函数6.tabBar配置 二. 基本语法&#xff0c;事件&#xff0c;单位1. 语法2. 事件3. 单位 三. 数据响应式修改四 . 内置组件1. button2. image3. input4. 组件…

钓鱼攻击:相似域名识别及如何有效预防攻击

网络犯罪分子很乐意劫持目标公司或其供应商或业务合作伙伴的官方域名&#xff0c;但在攻击的早期阶段&#xff0c;他们通常没有这种选择。相反&#xff0c;在有针对性的攻击之前&#xff0c;他们会注册一个与受害组织的域名相似的域名 - 他们希望您不会发现其中的差异。此类技术…

opencv基础51-图像轮廓04-轮廓多种图形拟合讲解及示例

轮廓拟合&#xff08;Contour Fitting&#xff09;是指在图像处理中&#xff0c;通过一些数学模型或曲线拟合方法来近似描述图像中的轮廓。图像中的轮廓是指物体的边界&#xff0c;轮廓拟合可以用于提取、描述和分析物体的形状。 常用的轮廓拟合方法包括多项式拟合、贝塞尔曲线…

【刷题笔记8.9】LeetCode题目:两数相加

LeetCode题目2&#xff1a;两数相加 题目及描述 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设…

【uniapp】封装一个全局自定义的模态框

【需求描述】 在接口401处&#xff0c;需要实现全局提示并弹出自定义模态框的功能。考虑到uni-app内置的模态框和app原生提示框的自定义能力有限&#xff0c;我决定自行封装全局自定义的模态框&#xff0c;以此为应用程序提供更加统一且个性化的界面。 【效果图】 【封装】 主…

Ansible Playbook快速部署一主多从MySQL集群

部署目标&#xff1a; 1、快速部署一套一主两从的mysql集群 2、部署过程中支持交互式定义安装目录及监听端口号 部署清单目录结构&#xff1a; rootmaster:/opt/mysql# tree . . ├── group_vars │ └── all.yml ├── hosts ├── mysql.yml └── roles└── mys…

两个状态的马尔可夫链

手动推导如下公式。 证明&#xff1a; 首先将如下矩阵对角化&#xff1a; { 1 − a a b 1 − b } \begin {Bmatrix} 1-a & a \\ b & 1-b \end {Bmatrix} {1−ab​a1−b​} (1)求如下矩阵的特征值&#xff1a; { 1 − a a b 1 − b } { x 1 x 2 } λ { x 1 x 2 }…

Android Https

本质&#xff1a;在客户端和服务端使用非对称加密协商出一套对称密钥&#xff0c;每次发送数据前加密&#xff0c;收到后解密&#xff0c;达到加密传输 http ssl 在http之下增加了安全层&#xff0c;用于保障http的加密传输 HTTPS连接 TLS连接步骤 1.客户端发送 client h…

Apache Doris 入门教程25:通过开启 Debug 日志进行性能分析

Doris 的 FE 和 BE 节点的系统运行日志默认为 INFO 级别。通常可以满足对系统行为的分析和基本问题的定位。但是某些情况下&#xff0c;可能需要开启 DEBUG 级别的日志来进一步排查问题。本文档主要介绍如何开启 FE、BE节点的 DEBUG 日志级别。 不建议将日志级别调整为 WARN 或…

一维二维数组的指针于sizeof和strlen

目录 一维数组于指针的一些题二维数组于指针的一些题 一维数组于指针的一些题 对数组名的理解 数组名表示首元素地址 //两个例外&#xff1a; //sizeof&#xff08;数组名&#xff09;:表示计算整个数组的大小 //&数组名&#xff1a;这里取的也是整个数组的大小,除了他两以…

ArcGIS、ENVI、InVEST、FRAGSTATS技术教程

专题一 空间数据获取与制图 1.1 软件安装与应用讲解 1.2 空间数据介绍 1.3海量空间数据下载 1.4 ArcGIS软件快速入门 1.5 Geodatabase地理数据库 专题二 ArcGIS专题地图制作 2.1专题地图制作规范 2.2 空间数据的准备与处理 2.3 空间数据可视化&#xff1a;地图符号与注…

23.8.9总结

接下来是答辩后的完善&#xff1a; 轮播图在管理员处可以进行修改&#xff0c; 消息处用websocket实现实时更新&#xff0c; 管理员审核界面&#xff0c;未审核的文章不能点赞&#xff0c;评论&#xff0c;收藏&#xff0c;不能用前端页面&#xff0c; 评论用二级评论&…

(el-Table)操作:Element-plus 中Table 表格组件:多选修改成支持单选及表格相关样式的调整

Ⅰ、Element-plus 提供的 Table 表格组件与想要目标情况的对比&#xff1a; 1、Element-plus 提供 Table 组件情况&#xff1a; 其一、Element-ui 自提供的 Table 代码情况为(示例的代码)&#xff1a; // Element-plus 自提供的代码&#xff1a; // 此时是使用了 ts 语言环境…

.NET根据类的值进行序列化反序列化操作

前言&#xff1a; 在.NET种&#xff0c;序列化一般常用的方式是使用Newtonsoft.Json进行序列化和反序列化操作&#xff0c;比如创建一个Person类 public class Person {public string Name { get; set; }public int Age { get; set; } }序列化为json // 对象序列化为 JSONPe…

vuejs 设计与实现 - 快速diff算法

Vue.js 2 所采用的双端 Diff 算法。既然快速 Diff 算法如此高效&#xff0c;我们有必要了解它的思路。接下来&#xff0c;我们就着重讨论快速 Diff 算法的实现原理。 相同的前置元素和后置元素 快速 Diff 算法借鉴了纯文本 Diff 算法中预处理的步骤。 案例&#xff1a; 旧的…

数据结构-队列(C语言的简单实现)

简介 队列也是一种数据结构&#xff0c;队列也可以用来存放数字每次只能向队列里将入一个数字&#xff0c;每次只能从队列里获得一个数字在队列中&#xff0c;允许插入的一段称为入队口&#xff0c;允许删除的一段称为出队口它的原则是先进先出(FIFO: first in first out)&…

Java8实战-总结15

Java8实战-总结15 引入流流简介流与集合 引入流 流简介 要讨论流&#xff0c;先来谈谈集合&#xff0c;这是最容易上手的方式。Java 8中的集合支持一个新的stream方法&#xff0c;它会返回一个流(接口定义在java.util.stream.Stream里)。在后面会看到&#xff0c;还有很多其他…

自从学了C++之后,小雅兰就有对象了!!!(类与对象)(中)——“C++”

各位CSDN的uu们好呀&#xff0c;好久没有更新小雅兰的C专栏啦&#xff0c;话不多说&#xff0c;让我们进入类和对象的世界吧&#xff01;&#xff01;&#xff01; 类的6个默认成员函数 构造函数 析构函数 拷贝构造函数 类的6个默认成员函数 如果一个类中什么成员都没有&am…