【C++系列P4】‘类与对象‘-三部曲——[类](2/3)

news2024/11/28 18:52:16

 前言

  • 大家好吖,欢迎来到 YY 滴 C++系列 ,热烈欢迎!
  • 【 '类与对象'-三部曲】的大纲主要内容如下

  • 如标题所示,本章是【 '类与对象'-三部曲】三章中的第二章节——类章节,主要内容如下:

目录

一.类

1.类的组成与计算类的大小(含结构体内存对齐规则)

二. 空类的大小

三.内部类

四.类的六个默认成员函数

1.构造函数

一.什么时候需要自己写构造函数? 

二.构造函数可以使用重载和不可以使用重载的情况

2.析构函数 

一.什么时候需要自己写析构函数? 

3.拷贝构造函数  

一.什么时候需要自己写拷贝构造函数?   

二.默认拷贝构造(浅拷贝)的缺陷:

4.运算符重载函数

一.运算符重载函数和构造函数使用区别:

5.赋值重载函数

6.取地址与取地址重载

五.初始化列表

一.初始化列表和构造函数的关系

二.初始化列表基本结构 

三.初始化列表使用场景

四.尽量使用初始化列表初始化

五.成员变量在初始化列表中的初始化顺序


一.类

  1. C++兼容C,C语言中的结构体strcut也算是一种类,是public(公有)的,可以被类外直接访问。
  2. 类中的函数默认是内联函数,具体是否是内联函数编译器会判断。如果将其定义和声名分开,即类放在.h文件,定义函数放在.cpp文件,函数不为内联函数

1.类的组成与计算类的大小(含结构体内存对齐规则)

  •  访问限定符划分类中既有成员变量,又有成员函数

 

计算类的大小,只用考虑成员变量的大小

例如:上图中,类的大小为8字节

PS:内存对齐,本质上是牺牲空间换取效率。通过调整默认对齐数可以对这一过程进行动态调整。


二. 空类的大小

  • 没有成员变量的类对象,需要 1byte ,是为了占位,表示对象存在.

三.内部类

概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。

注意:内部类就是外部类的友元类,参见友元类的定义,内部类可以通过外部类的对象参数来访问外部类中 的所有成员。但是外部类不是内部类的友元。

 特性:

  • 内部类可以定义在外部类的public、protected、private都是可以的。
  • 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。
  • sizeof(外部类)=外部类,和内部类没有任何关系。

四.类的六个默认成员函数

特点:

  • 当没有显式定义(我们不主动写时),编译器会自动生成

1.构造函数(第一个)

  •  默认构造函数(3种):(1) 类自己生成的函数(2)无参 (3)全缺省的函数
  •  特征:  (不传参就可以调用)  

 构造函数的主要任务是初始化对象,如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义,编译器将不再生成。

  • 运作上看,当对象实例化时,编译器会自动调用
  • 形态上看,其名字与类名相同且无返回值
  • 注意点,构造函数允许重载

一.什么时候需要自己写构造函数? 

需要自己写的情况:

  •  一般情况下,有内置类型成员,要自己写(否则会初始化成随机值

不需要自己写的情况:

  • 内置类型成员都有缺省值时,且初始化符合要求,可以考虑让编译器自己生成
  • 全部都是自定义类型成员(例如:Stack),可以考虑让编译器自己生成

                             注意!!!


二.构造函数可以使用重载和不可以使用重载的情况

  •   构造函数可以用重载的情况:
typedef int DataType;
class Stack
{
public:
	Stack(DataType* a, int n)    //特定初始化
	{
		cout << "Stack(DataType* a, int n)" << endl;
		_array = (DataType*)malloc(sizeof(DataType) * n);
		if (NULL == _array)
		{
			perror("malloc申请空间失败!!!");
			return;
		}
		memcpy(_array, a, sizeof(DataType) * n);

		_capacity = n;
		_size = n;
	}
    //调用时可用以用d1,使用上方的构造函数
	Stack d1(int, 11); 
	//Stack d1(); // 不可以这样写,会跟函数声明有点冲突,编译器不好识别
	Stack d2;
    //调用时可以用d2,使用下方的构造函数

	Stack(int capacity = 4)    //构造函数(全缺省)
	{
		cout << "Stack(int capacity = 4)" << endl;
		_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++;
	}

	void Pop()
	{
		if (Empty())
			return;
		_size--;
	}

	DataType Top() { return _array[_size - 1]; }
	int Empty() { return 0 == _size; }
	int Size() { return _size; }
~Stack()
	{
		cout << "~Stack()" << endl;
		if (_array)
		{
			free(_array);
			_array = NULL;
			_capacity = 0;
			_size = 0;
		}
	}

private:
	void CheckCapacity()
	{
		if (_size == _capacity)
		{
			int newcapacity = _capacity * 2;
			DataType* temp = (DataType*)realloc(_array, newcapacity * sizeof(DataType));
			if (temp == NULL)
			{
				perror("realloc申请空间失败!!!");
				return;
			}
			_array = temp;
			_capacity = newcapacity;
		}
	}*/
private:
	DataType* _array;
	int _capacity;
	int _size;
};
  • 构造函数不能用重载的情况:无参调用存在歧义
// 构成函数重载
	// 但是无参调用存在歧义
	  Date()
	{
		_year = 1;
		_month = 1;
		_day = 1;
	}

	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

2.析构函数 (第二个)

析构函数的主要任务是清理对象;

  • 运作上看,当对象生命周期结束时,编译器会自动调用
  • 形态上看,其在类名前加上~且无返回值
  • 注意点,析构函数不允许重载

默认析构函数与默认构造函数类似,编译器对内置类型成员不做处理,对自定义类型会去调用它的析构函数。


一.什么时候需要自己写析构函数? 

需要自己写的情况:

  • 有动态申请资源时,需要自己写析构函数释放空间。(防止内存泄漏

不需要自己写的情况:

  • 没有动态申请资源时,不需要自己写,系统会自动回收空间。
  • 需要释放资源的对象都是自定义类型时,不需要自己写


3.拷贝构造函数  (第三个)

行为:

  • 在创建对象时,创建一个与已存在对象一模一样的新对象

拷贝构造函数:

  • 只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰)
  • 在用已存在的类类型对象创建新对象时由编译器自动调用(区分于构造函数)
  • 拷贝构造函数构造函数的一个重载形式
已知类Date,已经有实例化的对象 Date d1;
此时想得到一个和d1一模一样的对象d2;
Date d2(d1);
类中若有拷贝构造Date (const Date d);
直接进行调用;
d2传给没有显示的this指针,d1传给const Date d;
Date d2(const Date d1)
  • 拷贝构造函数的参数只有一个且必须是类类型对象引用
当拷贝构造函数为 Date(const Date &d);//引用
Date(const Date d);//错误写法

Date(const Date &d)
	{
		this->_year = d.year;
		this->_month =d.month;
		this->_day =d.day;
	}
//this 为d2的指针,d为拷贝的类d1
  • 原因:【使用传值方式编译器直接报错,因为会引发无穷递归调用】(错误方式) 

       


一.什么时候需要自己写拷贝构造函数?   

默认生成的拷贝构造函数为:浅拷贝

需要自己写的情况:

  • 自定义类型必须使用拷贝构造(深拷贝) 

不需要自己写的情况:

  • 内置类型直接拷贝(浅拷贝/值拷贝)

例:Date类中都是内置类型,默认生成的拷贝构造函数为浅拷贝可以直接用;

而Stack类为自定义类型,其中有a指针指向一块新开辟的空间。此时需要自己写拷贝构造函数。


二.默认拷贝构造(浅拷贝)的缺陷:

浅拷贝的缺陷(默认拷贝构造运用 引用 防止死递归的后遗症)


4.运算符重载函数(第四个)

运算符重载:

  • 参数类型:const T& (传递引用可以提高传参效率) 
  • 函数名:关键字operator后面接需要重载的运算符符号
  • 函数原型:返回值类型+operator操作符+(参数列表)

运算符重载 底层转化演示:

 注意:

  • 不能通过连接其他符号来创建新的操作符:例如operator@
  • 重载操作符必须有一个类型参数
  • 用于内置类型的运算符,其含义不能改变:例如+
  • 作为类成员函数重载时,其形参看起来比操作数少一个(因为成员函数的第一个参数为隐藏的this)
  • .* / :: /sizeof/ ?: /./这五个运算符不能重载 

一.运算符重载函数和构造函数使用区别:


5.赋值重载函数(第四个的分支)

赋值运算符重载格式:

  • 参数类型:const T& (传递引用可以提高传参效率) 
  • 返回值类型:T&  (返回引用可以提高返回的效率,有返回值的目的是为了支持连续赋值
  • 检测是否可以自己给自己赋值
  • 返回 *this:(对this指针解引用,要符合连续赋值的含义)

  • 赋值运算符只能重载成为类的成员函数而不能重载成全局函数(如果重载成全局函数,编译器会生成一个默认运算符重载)
  • 用户没有显示实现时,编译器会生成一个默认赋值运算符重载以值的方式(浅拷贝)逐字节拷贝。(注意点:内置类型成员变量直接赋值,只有自定义成员变量需要调用对应的赋值运算符重载


6.取地址与取地址重载(第五个&第六个)

引入: 内置类型取地址时有取地址操作符,而自定义类型呢?于是出现了取地址重载。它用到的场景非常少,可以说取地址重载——补充这个语言的完整性,更加系统。 

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

  • 这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比如不想让别人获取到指定的内容! (设为nullptr)

代码演示:

class Date
{ 
public :
 Date* operator&()
 {
 return this ;
// return nullptr;让普通成员的this指针不被取到
 }
 
 const Date* operator&()const
 {
 return this ;
 }
private :
 int _year ; // 年
 int _month ; // 月
 int _day ; // 日
};

五.初始化列表


一.初始化列表和构造函数的关系

引入:构造函数调用之后,对象中已经有了一个初始值,但是不能将其称为对对象中成员变量的初始化, 构造函数体中的语句只能将其称为赋初值,而不能称作初始化。因为始化只能初始化一次,而构造函数体内可以多次赋值。


二.初始化列表基本结构 

初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中初始值或表达式

代码展示: 

class Date
{
public:
  Date(int year, int month, int day)   初始化列表
   : _year(year)
   , _month(month)
   , _day(day)
   {}
 
private:
 int _year;
 int _month;
 int _day;
};

三.初始化列表使用场景

  1. 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
  2. 类中包含以下成员,必须放在初始化列表位置进行初始化:
  • 引用成员变量
  • const成员变量
  • 自定义类型成员(且该类没有默认构造函数时 )

缺省值与初始化列表的关系: (下列代码中 int x 有演示)

  • 初始化列表没显式定义,缺省值给到初始化列表
  • 初始化列表显式定义,以初始化列表为主

代码展示: 

class A
{
  public:                内置类型可以放到初始化列表中初始化
    A(int a)
    :_a(a)
    {}
  private:
    int _a;
};

class B
{
  public:
    B(int a, int ref)      必须放到初始化列表中进行初始化
    :_aobj(a)
    ,_ref(ref)
    ,_n(10)
    {}

  private:
    A _aobj; // 没有默认构造函数  (无参/全缺省/默认生成)
    int& _ref; // 引用
    const int _n; // const 

    int x = 3;    缺省值为3,缺省值是给初始化列表的
                但是如果初始化列表中显式定义,则以初始化列表为主
};

四.尽量使用初始化列表初始化

  • 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量一定会先使用初始化列表初始化

五.成员变量在初始化列表中的初始化顺序

  • 成员变量在类中声明次序就是其在初始化列表中的初始化顺序与其在初始化列表中的先后次序无关 

图示:

 

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

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

相关文章

CodeForces..学习读书吧.[简单].[条件判断].[找最小值]

题目描述&#xff1a; 题目解读&#xff1a; 给定一组数&#xff0c;分别是 “时间 内容”&#xff0c;内容分为00&#xff0c;01&#xff0c;10&#xff0c;11四种&#xff0c;求能够得到11的最小时间。 解题思路&#xff1a; 看似00&#xff0c;01&#xff0c;10&#xff0…

完整卸载office以及重装office 2021

完整卸载office以及重装 一.背景 之前很早安装的word最近发现打开&#xff0c;编辑等操作都很卡&#xff0c;而且占用的CPU很多&#xff0c;20%左右&#xff0c;而在网上搜索了一些结果无法解决问题后&#xff0c;决定卸载重装 二. 卸载的建议方法 直接参考官方链接从PC卸载…

华为OD机试之租车骑绿岛(Java源码)

租车骑绿岛 题目描述 部门组织绿岛骑行团建活动。租用公共双人自行车&#xff0c;每辆自行车最多坐两人&#xff0c;最大载重M。 给出部门每个人的体重&#xff0c;请问最多需要租用多少双人自行车。 输入描述 第一行两个数字m、n&#xff0c;分别代表自行车限重&#xff0c;部…

k8s 对外服务之 ingress|ingress的对外暴露方式|ingress http,https代理|ingress nginx的认证,nginx重写

k8s 对外服务之 ingress|ingress的对外暴露方式|ingress http&#xff0c;https代理|ingress nginx的认证&#xff0c;nginx重写 一 Ingress 简介二 Ingress 组成三 ingress 暴露服务的方式四 部署 nginx-ingress-controller4.1 修改 ClusterRole 资源配置4.2 DaemonSetHostNet…

STM32HAL库RS485-ModBus协议控制伺服电机

STM32HAL库RS485-ModBus协议控制伺服电机 一个月前&#xff0c;接手了一个学长的毕设小车&#xff0c;小车采用rs485通信的modbus协议驱动轮毂电机&#xff0c;与往常我学习的pwm控制电机方法大相径庭&#xff0c;在这里以这篇博客记录下该学习过程。 小车主要架构 电机型号 …

Python期末复习题库(上)——“Python”

小雅兰期末加油冲冲冲&#xff01;&#xff01;&#xff01; 1. (单选题) Python源程序的扩展名为&#xff08; A &#xff09; A. py B. c C. class D. ph 2. (单选题) 下列&#xff08; A &#xff09;符合可用于注释Python代码。 A. # B. */ C. // D. $ 3. (单选题)下列…

SMARTPHONE PLATFORM st解决方案

智能手机是最常用的计算设备。 它们展示了强大的硬件功能和复杂的操作系统&#xff0c;支持高级功能和人工智能应用、互联网和云访问、图像和视频采集、游戏以及语音通话和短信等核心电话功能。 要执行如此多样的应用&#xff0c;智能手机必须包含许多设备&#xff0c;包括大量…

一、电路分析的变量

点我回到主目录 ------------------------------------------------------------------------------------------------------------------------- 目录 1.电流 2.电压 3.功率 4.关联参考方向 5.电路吸收或发出功率的判断 1.电流 •电流 单位A&#xff08;安培…

vue基于Python的图书商城销售系统qo85w

系统以浏览器/服务器模式即B/S模板式为基础。本系统使用MySQL数据库,利用Python开发的操作系统&#xff1b;主要的功能有个人中心、用户管理、图书资讯管理、图书类型管理、图书信息管理、爬虫管理、留言板管理、系统管理、订单管理等组成。 本文首先介绍了现代化图书销售系统管…

2023电工杯B题全保姆论文讲解手把手教程 人工智能影响评价

更新&#xff1a;电工杯B题全保姆论文成品教程&#xff0c;手把手教你完成高质量成品 这次b题是这一道问卷分析题目&#xff0c;是我最擅长的题目之一了&#xff0c;问卷分析看起来简单&#xff0c;实际上没那么那简单&#xff0c;考验的是我们能不能把数据描述清楚&#xff0…

2023哈佛大学博士后/访问学者研究班一览

哈佛大学是全球顶尖的高等教育机构之一&#xff0c;其所拥有的丰富资源和卓越师资吸引了来自全球各地的优秀学者前来攻读博士学位或作为访问学者进行研究。而博士后访问学者研究班则是哈佛大学提供给这些博士后访问学者的一个重要平台。博士后访问学者研究班是一个跨学科的研究…

echarts 被封装后多次复用,图表被覆盖,解决方法

场景&#xff1a;为了方便样式统一&#xff0c;封装了一个盒子&#xff0c;其中包含echarts&#xff0c;option是从父组件传来的 问题&#xff1a; 多个父级页面使用这个盒子后&#xff0c;发现只有第一个盒子展示图表&#xff0c;但展示的是最后一个图片的样式&#xff0c;其他…

【数据结构】如何应用堆解决海量数据的问题

堆(Heap数据结构堆在计算机科学中有着广泛的应用&#xff0c;今天来介绍两种堆的应用&#xff1a;堆排序、Top-k问题&#x1f349; 堆排序 ​ 堆排序是一种基于堆数据结构的排序算法。它的基本思想是&#xff0c;将待排序的序列构建成一个大根堆&#xff08;或小根堆&#xff…

三展齐发,DBF户外展、高博会、健身展隆重开幕,火爆现场燃炸鹏城!

5月25日&#xff0c;深圳建设国家体育消费试点城市系列活动&#xff0c;第四届DBF深圳国际户外运动博览会&#xff0c;DBF深圳国际高尔夫运动博览会暨深圳国际健身运动博览会&#xff08;以下简称DBF运动户外生活展&#xff09;在深圳国际会展中心5.7号馆盛大举办&#xff01;开…

recurdyn接触特征参数含义

一般接触特征设置 Static Threshold Velocity静态门槛速度&#xff1a;判断静态摩擦和动态摩擦的标准&#xff0c;若相对速度小于此值&#xff0c;摩擦为静摩擦&#xff1b;若相对速度大于此值&#xff0c;摩擦为动摩擦。静态摩擦区域内摩擦系数计算函数为 Dynamic Threshold V…

【网络编程】详解UDP/TCP套接字的创建流程+守护进程

目录 一、网络编程套接字 1、一些概念 1.1源IP地址和目的IP地址 1.2端口号port 1.3TCP和UDP的性质 1.4网络字节序、IP地址类型转换、数据接收与发送函数、popen函数 2、UDP套接字 2.1UDP服务器创建流程 2.2UDP客户端创建流程 2.3创建socket套接字 2.4绑定套接字对应…

模仿抖音直播商城带货打赏功能做一个app系统

随着人们生活和互联网的高度整合&#xff0c;越来越多的人开始转变自身消费模式&#xff0c;从实体店购物逐渐转向足不出户即可享受购物快感的网上购物。许多企业看到了电子商务背后隐藏的巨大价值&#xff0c;想要寻找合适的开发商建立属于自己的电商直播系统&#xff0c;那么…

【新星计划·2023】网工知识——OSPF讲解

OSPF ( Open Shortest Path First开放式最短路径优先)是一种动态路由协议&#xff0c;属于内部网关协议( Interior Gateway Protocol&#xff0c;简称IGP )&#xff0c;是基于链路状态算法的路由协议。 一、OSPF是什么&#xff1f; OSPF意思是指一个内部网关协议(Interior Ga…

阿里云短信验证接口调用

需要的maven依赖 <!-- 升级版 SDK这是一个短信 --> <dependency> <groupId>com.aliyun</groupId> <artifactId>dysmsapi20170525</artifactId> <version>2.0.23</version> </dependency> package com.service.thereServ…

融合改进Sine混沌映射的新型粒子群优化算法(NIPSO)-附代码

融合改进Sine混沌映射的新型粒子群优化算法(NIPSO) 文章目录 融合改进Sine混沌映射的新型粒子群优化算法(NIPSO)1.粒子群优化算法2. 改进粒子群优化算法2.1 改进的 Sine 混沌映射2.2 粒子群改进 3.实验结果4.参考文献5.Matlab代码6.Python代码 摘要&#xff1a;为了应对传统粒子…