C++中的类

一,类的定义

class classname
{//类体由成员函数和成员变量组成};

class为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面分 号不能省略。

类的两种定义方式:

  1. 声明和定义全部放在类体中,需注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理。
  2. 类声明放在.h文件中,成员函数定义放在.cpp文件中,注意:成员函数名前需要加类名::

二,类的访问限定符

  1. 访问限定符有三种分别为 public private protected
  2. public:类内类外都可以直接访问
  3. private:只有类内成员可以访问,类外成员不可以访问
  4. protected:只有类内成员可以访问,类外成员不可以访问
  5. C++中如果没有明确声明,类中的所有成员和函数都是私有的,即private
  6. 访问限定符的作用范围为从该限定符开始一直到下一个限定符,或者类的结束

三,类中的this指针

this指针的相关特性

  1. this指针只作用于类的内部
  2. 类中的非静态成员函数其参数列表中都有一个this指针,this指针的传递由编译器帮组我们完成,不需要用户主动传参
  3. this指针指向当前对象,被const所修饰,不可被修改
  4. 当我们在类的内部调用成员函数或者成员变量时(非静态),是以this->(成员函数或者成员变量),但是this->一般可以省略

关于this指针的小练习

// 1.下面程序编译运行结果是?  A、编译报错  B、运行崩溃  C、正常运行
class A
{
public:void Print(){cout << "Print()" << endl;}
private:int _a;
};
int main()
{A* p = nullptr;p->Print();return 0;
}
// 1.下面程序编译运行结果是?  A、编译报错  B、运行崩溃  C、正常运行
class A
{
public:void PrintA(){cout << _a << endl;}
private:int _a;
};
int main()
{A* p = nullptr;p->PrintA();return 0;
}

  1. 第一个正常运行,因为void Print()内部没有调用成员函数和成员变量,所以就没有用到this指针,所以没有报错能正常运行
  2. 第二个报错,因为void Print()内部用到了成员变量,也就用到了成员变量,所以会报错

四,类的6个默认成员函数

构造函数

  1. 函数名与类名相同,创建对象时由编译器自动调用,没有返回值
  2. 主要任务不是开辟空间创建对象,而是用于初始化成员函数
  3. 构造函数可以重载
  4. 如果我们没有显示的在类中写构造函数,编译器会自动的帮我们生成一个无参的默认构造函数,该默认构造函数在构建对象时会调用成员变量的构造函数(只对自定义类型生效)
  5. :C++11 中针对内置类型成员不初始化的缺陷,又打了补丁,即:内置类型成员变量在 类中声明时可以给默认值。

析构函数

  1. 对象在销毁时会自动调用析构函数,完成对象中资源的清理工作
  2. 析构函数名是在类名前加上字符 ~,无参数无返回值类型
  3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构 函数不能重载
  4. 对象生命周期结束时,C++编译系统系统自动调用析构函数
  5. 如果我们没有显示的在类中写析构函数,编译器会自动的帮我们生成一个析构函数数,该析构函数在对象销毁时会调用成员变量的析构函数

拷贝构造函数

  1. 拷贝构造函数是构造函数的一个重载形式,函数名与类名相同,没有返回值
  2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错, 因为会引发无穷递归调用。
  3. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按 字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。
  4. 类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请 时,则拷贝构造函数是一定要写的,否则就是浅拷贝。
  5. 拷贝构造函数典型调用场景:
  • 使用已存在对象创建新对象
  • 函数参数类型为类类型对象
  • 函数返回值类型为类类型对象

参数不是类类型对象的引用错误示例如下:

class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}// Date(const Date& d)   // 正确写法Date(const Date& d)// 错误写法:编译报错,会引发无穷递归{_year = d._year;_month = d._month;_day = d._day;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;Date d2(d1);return 0;
}

错误原因如下:

直接使用浅拷贝错误示例如下:

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(s1);return 0;
}

运行结果如下:

原因:程序退出时s2,s1都需要调用析构函数对内存进行释放,s2先调用析构函数对所申请的空间进行释放,这是s1并不知道内存已经被释放了,又因为浅拷贝指针指向的是同一块空间,对已经释放过的空间再次进行释放,必然会报错

赋值运算符重载
运算符重载
  1. 不能通过连接其他符号来创建新的操作符:比如operator@
  2. 重载操作符必须有一个类类型参数
  3. 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义
  4. 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐 藏的this
  5.  .  *   ::   sizeof   ?: . 注意以上5个运算符不能重载
赋值运算符重载
  1. 参数类型:const T&,传递引用可以提高传参效率
  2. 返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
  3. 返回*this :要复合连续赋值的含义
  4. 用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝
  5. 内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符 重载完成赋值。
  6. 如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必 须要实现,原因与上述拷贝构造相同
  7. 赋值运算符只能重载成类的成员函数不能重载成全局函数,示例如下:
class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}int _year;int _month;int _day;
};}// 赋值运算符重载成全局函数,注意重载成全局函数时没有this指针了,需要给两个参数Date& operator=(Date& left, const Date& right){if (&left != &right){left._year = right._year;left._month = right._month;left._day = right._day;}return left;// 编译失败:// error C2801: “operator =”必须是非静态成员

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

前置++和后置++重载
  1. 前置++和后置++都是一元运算符,为了让前置++与后置++形成能正确重载

C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器 自动传递

前置++如下:

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

后置++如下:

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

五,const成员

  1. 将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数 隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改(上文中提到的this被const修饰,是指针自身不能被修改)。

六,再谈构造函数

  1. 构造函数体中的语句只能将其称为赋初值,而不能称作初始化。因为初始化只能初始 化一次,而构造函数体内可以多次赋值。
  2. 所以我们引进一个新的概念初始化列表

初始化列表

  1. 以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟 一个放在括号中的初始值或表达式,表现形式如下:
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. 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后 次序无关
  3. 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量, 一定会先使用初始化列表初始化。
  4. 类中包含以下成员,必须放在初始化列表位置进行初始化
  • 引用成员变量
  • const成员变量
  • 自定义类型成员(且该类没有默认构造函数时)

explicit关键字

  1. 构造函数不仅可以构造与初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值 的构造函数,还具有类型转换的作用。
  2. 单参构造函数,没有使用explicit修饰,具有类型转换作用
  3. explicit修饰构造函数,禁止类型转换

七,static成员

static成员概念

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

计算程序中创建出了多少个类对象

class A
{
public:A() { ++_scount; }A(const A& t) { ++_scount; }~A() { --_scount; }static int GetACount() { return _scount; }
private:static int _scount;
};
int A::_scount = 0;void TestA()
{cout << A::GetACount() << endl;A a1, a2;A a3(a1);cout << A::GetACount() << endl;
}int main()
{TestA();return 0;
}

答案:是一个

static成员性质

  1. 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区
  2. 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明
  3. 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问
  4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
  5. 静态成员也是类的成员,受public、protected、private 访问限定符的限制
  6. 静态成员函数不可以调用非静态成员函数
  7. 非静态成员函数可以调用类的静态成员函数

八,友元

友元函数

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

友元分为:友元函数和友元类

  1. 友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在 类的内部声明,声明时需要加friend关键字。
  2. 友元函数可访问类的私有和保护成员,但不是类的成员函数
  3. 友元函数不能用const修饰
  4. 友元函数可以在类定义的任何地方声明,不受类访问限定符限制
  5. 一个函数可以是多个类的友元函数
  6. 友元函数的调用与普通函数的调用原理相同

友元类

  1. 友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员
  2. 友元关系是单向的,不具有交换性(A为B的友元类,A可以访问B中的所有私有成员函数和变量,但是B不能访问A中的私有成员函数和成员)
  3. 友元关系不能传递(如果C是B的友元, B是A的友元,则不能说明C是A的友元)
  4. 友元关系不能继承,在继承位置再给大家详细介绍

九,内部类

  1. 如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类, 它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越 的访问权限
  2. 内部类就是外部类的友元类,参见友元类的定义,内部类可以通过外部类的对象参数来访 问外部类中的所有成员。但是外部类不是内部类的友元
  3. 内部类可以定义在外部类的public、protected、private都是可以的
  4. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名
  5. sizeof(外部类)=外部类,和内部类没有任何关系

十,匿名对象

  1. 假设有一个类的类名为A,定义对象时不能  A+对象名+(),这样编译器无法识别是函数声明还是定义对象
  2. 可以A+()定义对象,作用域为该行

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

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

相关文章

从集合论到位运算

前言 本文将扫清位运算的迷雾&#xff0c;在集合论与位运算之间建立一座桥梁。 在高中&#xff0c;我们学了集合论&#xff08;set theory&#xff09;的相关知识。例如&#xff0c;包含若干整数的集合 S{0,2,3}。在编程中&#xff0c;通常用哈希表&#xff08;hash table&…

自然资源-农村土地流转知识全解

自然资源-农村土地流转知识全解 随着农村经济的发展和城市化进程的加快&#xff0c;农村土地面临着多方面的压力&#xff0c;如人口增长、城市扩张、环境恶化等。这些压力导致了农村土地利用率低、经济效益差、农民收入水平低、农村社会经济不发达等问题。因此&#xff0c;改变…

计算机网络学习2

文章目录 信道复用技术 第三章数据链路层概述数据链路层的三个重要问题封装成帧和透明传输差错检测可靠传输的相关基本概念可靠传输的实现机制停止等待协议回退N帧协议选择重传协议 点对点协议PPP共享式以太网网络适配器和MAC地址CSMA_CD协议的基本原理共享式以太网的争用期共享…

备战十一届大唐杯国赛预选赛

这次省赛带了太多个省一了&#xff0c;具体可看下面的图片&#xff0c;只放了一部分。目前根据可靠消息&#xff0c;应该还有个预选赛和去年一样&#xff0c;就是还会考一次仿真。如果说通过了就是国二起步然后去北方工业争夺国一国二&#xff0c;没过的话就是国三。 每…

<MySQL> 表的增删改查 - 基本查询

目录 前言&#xff1a; 一、表的插入 &#xff08;一&#xff09;指定列插入和多行插入 &#xff08;二&#xff09;全列插入 &#xff08;三&#xff09;插入选择更新 &#xff08;四&#xff09;替换数据 二、表中的数据查询 &#xff08;一&#xff09;select查询语…

【SQL学习进阶】从入门到高级应用【三范式】

文章目录 什么是数据库设计三范式三范式一对多怎么设计多对多怎么设计一对一怎么设计最终的设计 &#x1f308;你好呀&#xff01;我是 山顶风景独好 &#x1f495;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01; &#x1f495;希望您在这里可以感受到一份…

sql注入-布尔盲注

布尔盲注&#xff08;Boolean Blind SQL Injection&#xff09;是一种SQL注入攻击技术&#xff0c;用于在无法直接获得查询结果的情况下推断数据库信息&#xff1b;它通过发送不同的SQL查询来观察应用程序的响应&#xff0c;进而判断查询的真假&#xff0c;并逐步推断出有用的信…

低代码选型要注意什么问题?

低代码选型时&#xff0c;确实需要从多个角度综合考虑&#xff0c;以下是根据您给出的角度进行的分析和建议&#xff1a; 公司的人才资源&#xff1a; 评估团队中是否有具备编程能力的开发人员&#xff0c;以确保能够充分利用低代码平台的高级功能和进行必要的定制开发。考察实…

告别繁琐SQL,4K星开源神器让数据库管理像聊天一样简单!

大家好&#xff0c;今天我要给大家介绍一个超级棒的开源项目——SQL Chat。如果你是一名开发者&#xff0c;数据库管理员&#xff0c;或者对数据分析感兴趣&#xff0c;那你绝对不能错过这个神器。SQL Chat&#xff0c;一个近4K星的GitHub项目&#xff0c;它将彻底改变你与数据…

本地安装AI大模型

使用ollmam安装llmama3等模型 1.打开ollmam下载对应系统的软件&#xff0c;安装即可 官网&#xff1a;Ollama&#xff0c; 安装直接点就就行了&#xff0c;没有其他操作 2.安装模型 在官网找到对于的模型下载命令 记录命令:ollama run llama3 打开一个cmd窗口&#xff0c;输…

【已解决】HtmlWebpackPlugin.getHooks is not a function

安装下面的依赖&#xff0c;获得 html-webpack-plugin 的 beta 版本 npm i html-webpack-pluginnext --save此问题在github上有讨论&#xff1a;https://github.com/facebook/create-react-app/issues/5465

【UE5.1 角色练习】09-物体抬升、抛出技能 - part1

前言 在上一篇&#xff08;【UE5.1 角色练习】08-传送技能&#xff09;的基础上继续实现控制物体抬升、抛出的功能。 效果 步骤 一、准备技能动画 1. 在项目设置中新建一个操作映射&#xff0c;这里命名为“Skill_GravityControl”&#xff0c;用按键4触发 2. 通过IK重定向…

git远程仓库限额的解决方法——大文件瘦身

Git作为世界上最优秀的分布式版本控制工具&#xff0c;也是优秀的文件管理工具&#xff0c;它赋予了项目成员对项目进行远程协同开发能力&#xff0c;因此受到越来越多的行业从业人员的喜爱。很多优秀的项目管理平台&#xff0c;比如国内的Gitee&#xff0c;国外的Github&#…

MySQL 一条SQL查询/更新语句是如何执行的?

MySQL 一条SQL查询语句是如何执行的&#xff1f; 1 连接器 首先客户端需要先跟服务端进行连接 2 查询缓存 MySQL 5.7 以及之前的版本会查询MySQL缓存&#xff0c;存储是键值对形式的 分析器 对SQL进行词法分析【会生成词法树】以及语法分析 词法分析&#xff1a; 主要负…

社交媒体数据恢复:淘宝旺信

根据搜索结果&#xff0c;阿里旺旺聊天记录的恢复方法如下&#xff1a; 运行阿里旺旺在旺旺面板底部点击小喇叭图标在打开的消息管理器窗口右上角点击"搜索"点击"高级搜索"设置所需查找的时间段---"搜索" 此外&#xff0c;在阿里旺旺的云存储中…

基于稀疏辅助小波和线性时不变滤波器的惯性传感器步态周期分割方法(MATLAB R2018A)

每个人在肌肉骨骼状况、生理状况、心理特征以及个人行走的“风格”等方面都有各自的特点&#xff0c;因此&#xff0c;每个人都有自己的步态指纹。这意味着可以根据步态特征来进行身份识别。基于步态的身份识别是生物特征识别的一个新兴领域。其机制有3个显著的优点&#xff1a…

STM32高级控制定时器应用之检测输入PWM周期和占空比

目录 概述 1 PWM 输入模式 1.1 原理介绍 1.2 应用实例 1.3 示例时序图 2 使用STM32Cube配置工程 2.1 软件环境 2.2 配置参数 2.3 生成项目文件 3 功能实现 3.1 PWM占空比函数 3.2 输入捕捉回调函数 4 功能测试 4.1 测试软件框架结构 4.2 实验实现 4.2.1 测试实…

整数之间的赋值问题

前言&#xff1a;我们在初学C语言的时候&#xff0c;总是避免不了一些数据类型的转换&#xff0c;例如int-->char&#xff0c;char-->int&#xff0c;如果我们仅仅只学习这些语法&#xff0c;而不去了解底层原理&#xff0c;对于这些输出的内容&#xff0c;我们可能会感觉…

2024还不会安装NodeJs

2024还不会安装NodeJs 1、官网下载 由于本地是windows&#xff0c;所以选择 Prebuilt Installer 64位 NodeJs官网下载 LTS长期支持版本 当然这里我用的 Snipastate 截屏软件&#xff0c;这里也配下载链接 Snipasate下载链接 2、配置环境变量 由于是自己的电脑&#xff0c…

SpringBoot启动流程分析之设置系统属性spring.beaninfo.ignore、自定义banner图(五)

SpringBoot启动流程分析之设置系统属性spring.beaninfo.ignore、自定义banner图&#xff08;五&#xff09; 参考 目录 文章目录 SpringBoot启动流程分析之设置系统属性spring.beaninfo.ignore、自定义banner图&#xff08;五&#xff09;1、设置sping.beaninfo.ignore属性2、…