C++类和对象_C++回顾

面向对象和面向过程的区别

C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。

C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。

类大小的计算

结构体内存对齐规则

第一个成员在与结构体偏移量为0的地址处。

其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

        注意:对齐数=编译器默认的一个对齐数与该成员大小的较小值。

        VS中默认对齐数为8

结构体总体大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。

如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

参考之前写的文章:C进阶_结构体内存对齐-CSDN博客

除此之外,空类比较特殊,编译器给了空类一个字节来唯一标识这个类的对象。

class和struct的区别

C++需要兼容C语言,所以C++中struct可以当成结构体来使用。另外,C++中struct还可以用来定义类。和class定义类是一样的,区别是struct定义的类默认访问权限是public,class类定义的类默认访问权限是private。

使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显式地写出继承方式。

模板参数列表中,只有class和typename关键字,不存在struct。

this指针

C++编译器给每个“非静态的成员函数”增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”的操作,都是通过该指针去访问的。只不过所有操作对用户是透明的,即用户不需要来传递,编译器自动完成。

this指针的特性

this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。

只能在“成员函数”的内部使用。

this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参,所以对象中不存储this指针。

this指针是“成员函数”的第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。

this指针可以为空,当我们调用函数时,如果函数内部不需要使用到this,也就是不需要通过this指向当前对象并对其进行操作时才可以为空(当我们在其中什么都不放或者在里面随便打印一个字符串),如果调用的函数需要指向当前对象,并进行操作,则会发生错误(空指针引用),就跟C语言中不能进行空指针的解引用。

8个默认成员函数

构造函数 

概念

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

特性

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

其特征如下:

函数名与类名相同。

无返回值。

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

构造函数可以重载。

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

C++把类型分为内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类型,如int/char...自定义类型就是我们使用class/struct/union等自己定义的类型。编译器生成默认的构造函数会对自定义类型成员调用它的默认成员函数。C++11中针对内置类型成员不初始化的缺陷,又打了补丁,即:内置类型成员变量在类中声明时可以给默认值。

无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。注意:无参构造函数、全缺省构造函数、编译器默认生成的构造函数,都可以认为是默认构造函数。

explicit关键字

构造函数不仅可以构造与初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值的构造函数,还具有类型转换的作用。 

注意:构造函数体内的语句只能将其称为赋初值,而不能称作初始化。因为初始化只能初始化一次,而构造函数体内可以多次赋值。 

析构函数 

概念

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

特性

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

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

无参数无返回值类型。

一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意!析构函数不能重载!

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

编译器默认生成的析构函数,会对自定义类型成员调用它的析构函数。

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

拷贝构造函数

概念

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

特性

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

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

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

若未显式定义,编译器会生成默认的拷贝构造函数。默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。注意:在编译器生成的默认拷贝构造函数中,内置类型是按照字节方式直接拷贝的,而自定义类型是调用其拷贝构造函数完成拷贝的。

编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了,还需要自己显式实现吗?当然像日期类这样的类是没有必要的。类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请时,则拷贝构造函数一定要写,否则就是浅拷贝。

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

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

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

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

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

初始化列表

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

注意:

每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)。

类中包含以下成员,必须放在初始化列表位置进行初始化:

        引用成员变量

        const成员变量

        自定义类型成员(且该类没有默认构造函数时)

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

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

赋值运算符重载函数

运算符重载

为了增强代码的可读性,C++引入了运算符重载。

运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。

函数名字为:关键字operator后面接需要重载的运算符符号。

函数原型:返回值类型operator操作符(参数列表)。

注意:

        不能通过连接其它符号来创建新的操作符,如operator@

        重载操作符必须有一个类类型参数

        用于内置类型的运算符,其含义不能改变,例如:内置的类型+,不可以改变含义

        作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this指针

        应注意这些运算符不可以重载:

                (1).

                (2).*

                (3)::

                (4)sizeof

                (5)?:

如果运算符重载成全局的,就需要成员变量是公有的。要保证封装性,可以使用友元函数,或者放弃使用全局重载,重载成成员函数。

赋值运算符重载

赋值运算符重载格式

        参数类型:const T&,传递引用可以提高传参效率

        返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值

        检测是否给自己赋值

        返回*this:要符合连续赋值的含义

赋值运算符只能重载成类的成员函数不能重载成全局函数,因为:如果赋值运算符不显示实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数。

用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。也就是说,内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。

注意如果类中未涉及到资源管理,赋值运算符是否实现都可以。但是一旦涉及到资源管理,就必须要用深拷贝去实现了。

前置++和后置++重载

前置++:返回+1之后的结果。因为this指向的对象函数结束后不会销毁,所以以引用方式返回提高效率。

Data& operator++(){_day+=1;return *this;
}

后置++:和前置++一样,都是一元运算符。C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器自动传递。后置++是先使用后+1,因此需要返回+1之前的旧值,所以需要在实现时将this保存一份,然后给this+1

Data& operator++(int){Data temp(*this);_day+=1;return temp;
}

const成员

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

const函数与非const函数的调用规则

        在相同的函数参数及相同的名字的情况下,const函数与非const函数可以构成重载函数,但是const成员函数不能改变任何的非静态变量;

        const对象默认调用const成员函数,非const对象默认调用非const成员函数;

        在同时存在const函数和非const重载函数的前提下,若非const对象想调用const成员函数,则需要显示的转化,例如(const Student&)obj.getAge();

        若const对象想调用非const成员函数,同理进行强制类型转换const_cast<Student&>(constObj).getAge();(注意constObj一定要加括号)

当类中只有一种函数存在的情况

        非const对象可以调用const成员函数或者非const成员函数;

        const对象只能调用const成员函数,若直接调用非const成员函数编译器会报错。

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

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

友元

友元提供了一种突破封装的方式,可以提高便利。但是友元会增加耦合度,破坏封装,所以友元不宜多用。

友元函数

友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。

注意:

        友元函数可以访问类的私有和保护成员,但不是类的成员函数;

        友元函数不能用const修饰;

        友元函数可以在类定义的任何地方声明,不受类访问限定符限制;

        一个函数可以是多个类的友元函数;

        友元函数与普通函数的调用原理相同。

友元类

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。

        友元关系是单向的,不具有交换性

        友元关系不能传递

                如果B是A的友元,C是B的友元,则不能说明C是A的友元。

        友元关系不能继承

static成员

概念

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量。用static修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化。

特性

静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区;

静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明;

类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问;

静态成员函数没有隐藏的this指针,不能访问任何非静态成员;

静态成员也是类的成员,受public、protected、private访问限定符的限制;

静态成员函数不能直接调用非静态成员函数,非静态成员函数可以调用静态成员函数。

拷贝对象时,编译器的优化

https://bbs.huaweicloud.com/blogs/408995

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

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

相关文章

Excel·VBA时间范围筛选及批量删除整行

看到一个帖子《excel吧-筛选开始时间&#xff0c;结束时间范围内的所有记录》&#xff0c;根据条件表中的开始时间和结束时间构成的时间范围&#xff0c;对数据表中的开始时间和结束时间范围内的数据进行筛选 目录 批量删除整行&#xff0c;整体删除批量删除整行&#xff0c;分…

LeetCode 2865. 美丽塔 I,前后缀分离+单调栈

一、题目 1、题目描述 给你一个长度为 n 下标从 0 开始的整数数组 maxHeights 。 你的任务是在坐标轴上建 n 座塔。第 i 座塔的下标为 i &#xff0c;高度为 heights[i] 。 如果以下条件满足&#xff0c;我们称这些塔是 美丽 的&#xff1a; 1 < heights[i] < maxHeight…

HTML+CSS:炫酷登录切换

效果演示 实现了一个登录注册页面的切换效果&#xff0c;当用户点击登录或注册按钮时&#xff0c;会出现一个叠加层&#xff0c;其中包含一个表单&#xff0c;用户可以在表单中输入用户名和密码&#xff0c;然后点击提交按钮进行登录或注册。当用户点击返回按钮时&#xff0c;会…

操作系统----操作系统的特征

目录 1.并发&#xff1a; 2.共享&#xff1a; 3.虚拟&#xff1a; 4.异步&#xff1a; 操作系统包括以下4个特征&#xff1a;并发&#xff0c;共享&#xff0c;虚拟&#xff0c;异步 1.并发&#xff1a; 指两个或多个事件在同一时间间隔内发生。这些事件宏观上是同时发生…

边缘计算:挑战与机遇的平衡艺术

前言 边缘计算作为云计算的补充&#xff0c;通过在数据源近处进行数据处理&#xff0c;已经成为实现物联网&#xff08;IoT&#xff09;、自动驾驶、智慧城市等应用的重要技术。然而&#xff0c;边缘计算的发展和普及也面临不少挑战&#xff0c;同时也带来了巨大的机遇。 方向…

【Android】Android中的系统镜像由什么组成?

文章目录 总览Boot Loader 的加锁与解锁Boot 镜像内核RAM diskARM 中的设备树 (Device Tree) /System 和/Data 分区镜像参考 总览 各种Android设备都只能刷专门为相应型号的设备定制的镜像。 厂商会提供一套系统镜像把它作为“出厂默认”的 Android 系统刷在设备上。 一个完…

SpringCloudAlibaba系列之Nacos实战

目录 注意事项 参考资源 Nacos配置中心 初始化项目 进行Nacos相关配置 运行 Nacos注册中心 dubbo方式 对外暴露接口dubbo-api 服务提供者dubbo-provider 服务消费者dubbo-consumer 负载均衡客户端方法 服务提供者 服务消费者 注意事项 不管是使用Nacos配置中心&…

代码随想录 Leetcode144/94/145 二叉树的前/中/后序遍历

题目&#xff1a; 前&#xff1a; 中&#xff1a; 后&#xff1a; 代码&#xff08;首刷自解 2024年1月24日&#xff09;&#xff1a; //前序遍历&#xff0c;递归 class Solution { public:void funcOfRecursion(TreeNode* cur, vector<int>& vec) {if (cur null…

MySQL深入——16

MySQL如何保持高可用&#xff1f;&#xff1f; 主备延迟 主备延迟分为两类&#xff0c;一类主动比如软件升级&#xff0c;主库所在机器按照计划下线等&#xff0c;另外一类是被动&#xff0c;比如主库所在机器掉电。 在看这个概念之前&#xff0c;我们先来看看“同步延迟”&…

谈谈 RocketMQ 5.0 分级存储背后一些有挑战的技术优化

作者&#xff1a;斜阳 RocketMQ 5.0 提出了分级存储的新方案&#xff0c;经过数个版本的深度打磨&#xff0c;RocketMQ 的分级存储日渐成熟&#xff0c;并成为降低存储成本的重要特性之一。事实上&#xff0c;几乎所有涉及到存储的产品都会尝试转冷降本&#xff0c;如何针对消…

张量计算和操作

一、数据操作 1、基础 import torchx torch.arange(12) # x:tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])x.shape # torch.Size([12])x.numel() # 12x x.reshape(3, 4) # tensor([[ 0, 1, 2, 3], # [ 4, 5, 6, 7], # [ 8, 9, 10, 11]])torch.zeros((2…

自动化Web页面性能测试介绍

随着越来越多的用户使用移动设备访问 Web 应用&#xff0c;使得 Web 应用需要支持一些性能并不是很好的移动设备。为了度量和测试 Web 应用是不是在高复杂度的情况下&#xff0c;页面性能能满足用户的需求。 同时&#xff0c;随着 Web 应用的空前发展&#xff0c;前端业务逐渐…

插入排序

插入排序 概述步骤代码示例输出结果 概述 插入排序是一种最简单直观的排序算法&#xff0c;它的工作原理是通过创建有序序列和无序序列&#xff0c;然后再遍历无序序列得到里面每一个数字&#xff0c;把每一个数字插入到有序序列中正确的位置。 插入排序是一种简单直观的排序…

某马头条——day10

热文章数据查询 分布式任务调度xxl-job 概述 环境搭建 docker化部署 docker run -p 3306:3306 --name mysql57 \ -v /opt/mysql/conf:/etc/mysql \ -v /opt/mysql/logs:/var/log/mysql \ -v /opt/mysql/data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORDroot\ -d mysql:5.7 dock…

尝试给docker ubuntu22.04镜像添加远程访问桌面

实在时不愿折腾&#xff0c;但是ubuntu 镜像没有桌面&#xff0c;有些操作实在太难受了&#xff0c;效率也不高。硬着头皮上吧。幸亏这是个docker的镜像。要是个虚拟机&#xff0c;这折腾来去&#xff0c;直接崩溃了。docker的好处就是立马就能从头来过&#xff0c;秒级的删除安…

分辨率 时钟频率 lane速率计算

PCLK: pixel clock(像素频率) 计算方法如下&#xff1a; 以1920x1080p/60hz为例&#xff0c;total pixel&#xff1a;2200&#xff0c;total line&#xff1a;1125&#xff0c;filed rate&#xff1a;60Hz&#xff0c;那么&#xff1a;PCLK 2200*1125*60 148.5MHz&#xff1b…

ATF(TF-A)安全通告TF-V11——恶意的SDEI SMC可能导致越界内存读取(CVE-2023-49100)

目录 一、ATF(TF-A)安全通告TFV-11 (CVE-2023-49100) 二、透过事务看本质SDEI是干啥的呢&#xff1f; 三、CVE-2023-49100 1、GICv2 systems 2、GICv3 systems 四、漏洞修复 一、ATF(TF-A)安全通告TFV-11 (CVE-2023-49100) Title 恶意的SDEI SMC可能导致越界内存读取&am…

Spring Security架构

文章目录 过滤器回顾DelegatingFilterProxyFilterChainProxySecurityFilterChainSecurity Filters打印Security Filters将自定义过滤器添加到过滤器链 Handling Security ExceptionsSaving Requests Between AuthenticationRequestCachePrevent the Request From Being Saved R…

Mysql的备份以及恢复

第五章 MySQL的备份及恢复 5.1 MySQL日志管理 在数据库保存数据时&#xff0c;有时候不可避免会出现数据丢失或者被破坏&#xff0c;这样情况下&#xff0c;我们必须保证数据的安全性和完整性&#xff0c;就需要使用日志来查看或者恢复数据了 数据库中数据丢失或被破坏可能原…

Spring SpEL在Flink中的应用-与Filter结合实现数据动态分流

文章目录 前言一、POM依赖二、主函数代码示例三、FilterFunction实现总结 前言 SpEL表达式与Flink fiter结合可以实现基于表达式的灵活动态过滤。有关SpEL表达式的使用请参考Spring SpEL在Flink中的应用-SpEL详解。 可以将过滤规则放入数据库&#xff0c;根据不同的数据设置不…