【C++入门】类和对象(完)
前言
在谈论C++时,常常会涉及到一些高级特性和概念,比如初始化列表、static成员、友元、内部类、匿名对象等。这些概念在C++编程中起着非常重要的作用,对于想要深入了解C++语言的开发者来说,掌握这些知识是至关重要的。本文,我们将深入探讨这些概念,探讨它们的作用以及如何在实际中的应用。
1. 再谈构造函数
1.1 初始化列表
提到初始化列表,那就要再次谈及构造函数,初始化列表属于构造函数进行初始化的一种方式。
class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}
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;
};
定义一个类的对象时是这样的:
Date d1(2023,11,20);
这是对象的整体定义,成员变量的定义在哪儿?就是在初始化列表。
每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)。
对于一些特殊情况,就必须要使用初始化列表进行初始化:
- 引用成员变量
- const成员变量
- 自定义类型成员(且该类没有默认构造函数时)
初始化列表也可以与构造函数函数体内初始化结合使用:
这个是一个测试样例:
class A
{
public:A(int a):_a(a){}
private:int _a;
};Date(int year, int month, int day)
{_year = year;_month = month;_day = day;_n = 1; //报错:error C2530: “Date::_ref”: 必须初始化引用_ref = year; //报错:error C2789: “Date::_n”: 必须初始化常量限定类型的对象
}
private:int _year;int _month;int _day;int& _ref;const int _n;};
_ref和_n如果在函数体内初始化就会报错,const修饰会让其具备常属性,也就是说该变量只能在定义时初始化,引用类型也是,在定义时必须要初始化。
正确的构造函数写法应该是:
Date(int year, int month, int day): _n(1), _ref(_year)
{_year = year;_month = month;_day = day;
}
接下来就是它在C++语法设计时的细节问题:
class Date
{
public:Date(int year, int month, int day): _n(1) //类成员定义, _ref(year){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;int& _ref;const int _n;
};int main()
{Date d1(2023, 11, 20);// 对象整体定义return 0;
}
这里C++语法设计的有点过于复杂,构造函数执行完初始化列表内容之后,函数体内的成员变量也已经被定义
在没有执行赋值初始化操作之前,内置类型默认的随机值(但此时的全部成员变量都是已经被定义了的)。
其次就是自定义类型:
测试代码,比如:
class A
{
public:A(int a = 0) //注意这里给了缺省值:_a(a){}
private:int _a;
};class Date
{
public:Date(int year, int month, int day): _n(1), _ref(year){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;int& _ref;const int _n;A _obj;
};int main()
{Date d1(2023, 11, 20);return 0;
}
注意观察以下调试过程:
在初始化列表进行初始化时,自定义类型会自动调用默认构造函数。
注意:自定义类型A在构造函数中给了缺省值!!!
如果不给缺省值,就会直接报错(没有默认构造函数): error C2512: “A”: 没有合适的默认构造函数可用
解决方法有两种:
- 在A的构造函数中给缺省值
- 使用初始化列表
Date(int year, int month, int day): _n(1), _ref(year), _obj(10)
{_year = year;_month = month;_day = day;
}
之前我们提到C++打补丁支持声明时给缺省值:
class Date
{
public:Date(int year, int month, int day): _n(1), _ref(year), _obj(10){_year = year;_month = month;_day = day;}
private:int _year = 1; //在声明中给缺省值int _month;int _day;int& _ref;const int _n;A _obj;
};
这个缺省值其实就是给初始化列表的,在初始化列表中如果没有显示要求初始化就会使用这里的缺省值。
- 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化
当然也有初始化列表无法完成的情况:
有些初始化或检查的任务,初始化列表无法完成,比如:
class Stack
{
public:Stack(int n = 2):_a((int*)malloc(sizeof(int)*n)),_top(0),_capacity(n){if (_a == nullptr){perror("malloc fail");exit(-1);}memset(_a, 0, sizeof(int) * n);}
private:int* _a;int _top;int _capacity;
};
使用函数初始化数组的值,或者是开空间失败后的异常处理。
- 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关
看以下这个代码:
class A
{
public:A(int a):_a1(a), _a2(_a1){}void Print() {cout << _a1 << " " << _a2 << endl;}
private:int _a2;int _a1;
};int main()
{A aa(1);aa.Print();
}
它的输出结果是什么?
答案是_a1 = 1和_a2 = 随机值,声明次序就是其在初始化列表中的初始化顺序。所以它先初始化的是_a2,_a2使用_a1的值进行初始化,但此时_a1还未执行初始化,此时的_a1为随机值。
1.2 explicit关键字
看下面这段代码:
class A
{
public:A(int a):_a(a){}int _a = 0;};
void Test()
{A a1(1);A a2 = 2;// 内置类型隐式转换成自定义类型}
a2在进行初始化时发生了隐式转换:实际编译器背后会用2构造一个无名对象,最后用无名对象给a2对象进行赋值。
能支持整形2转换,是有A的int 单参数构造函数支持,如果使用int* 类型就不支持隐式类型转换了。
想要支持可以添加一个含int* 的单参数构造函数:
class A
{
public:A(int a):_a(a){}A(int* p){}int _a = 0;};
如果不想让这个隐式类型转换(强制类型转换还是可以的),就可以使用explicit关键字来修饰构造函数。
class A
{
public:explicit A(int a):_a(a){}int _a = 0;};
前边的示例是单参数,那多参数呢?
class Date
{
public:Date(int year, int month = 1, int day = 1): _year(year), _month(month), _day(day){}private:int _year;int _month;int _day;
};
如上,也是可以的,支持一个传参的半缺省(全缺省也可以)也是可以隐式类型转换。那可不可以支持多个内置类型隐式转换,C++11是可以的:
Date d1 = { 2023, 11, 10 };
但是只能如上这种写法。
多参数也是一样,如果不想要隐式类型转换,可以给构造函数加explicit。
2. static成员
static修饰有什么作用?
static修饰的成员变量或成员函数在类加载时执行,并且只会执行一次。
问题:实现一个类,计算程序中创建出了多少个类对象
使用全局变量计算:
int n = 0;class A
{
public:A() { ++n; }A(const A& t) { ++n; }~A() {}private:};A func()
{A aa;return aa;
}int main()
{n++;A aa;func();n++;cout << n << endl;return 0;
}
当前边存在修改n的情况,结果就不准确了,其次就是每次使用时都要将n置为0(其他类也可能使用过n);那有没有专属这个类的计数变量呢?使用static就可以很好的解决这个问题。
2.1 概念
用static修饰的成员变量,称之为静态成员变量;
用static修饰的成员函数,称之为静态成员函数。
静态成员变量一定要在类外进行初始化
class A
{
public:A() { ++count; }A(const A& t) { ++count; }~A() {}static int GetACount() { return count; }
private:static int count;
};int A::count = 0;
A func()
{A aa;return aa;
}int main()
{A aa;func();cout << A::GetACount() << endl;return 0;
}
2.2 特点
- 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区
- 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明
- 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问
- 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
- 静态成员也是类的成员,受public、protected、private 访问限定符的限制
总结:静态成员变量和静态成员函数,可以理解为受限制的全局变量和全局函数。专属于某个类,受类域和访问限定符的限制。
3. 匿名对象
匿名对象其实很简单我们看下面这个代码:
class Date
{
public:Date(int year, int month = 1, int day = 1): _year(year), _month(month), _day(day){}private:int _year;int _month;int _day;
};int main()
{vector<Date> v;Date d1(2023, 11, 1);v.push_back(d1);return 0;
}
在C++中的STL容器中我们要存储日期类的对象。每次存储还要创建一个对象,然后再存储,这样很麻烦,这里我们就可以使用匿名函数:
v.push_back(Date(2023, 10, 31));
匿名对象在这样场景下就很好用。匿名对象的生命周期只有这一行,执行完之后自动调用析构函数。
4. 友元
友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以
友元不宜多用
友元分为:友元函数和友元类
4.1 友元函数
友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字
前边在实现Date类的流插入、流提取中提到过。
友元函数的特点:
- 友元函数可访问类的私有和保护成员,但不是类的成员函数
- 友元函数不能用const修饰
- 友元函数可以在类定义的任何地方声明,不受类访问限定符限制
- 一个函数可以是多个类的友元函数
- 友元函数的调用与普通函数的调用原理相同
4.2 友元类
友元类(friend class)是指一个类可以访问另一个类的私有成员和保护成员。
比如:
class A {
private:int privateData;
protected:int protectedData;friend class B; // B是A的友元类
};class B {
public:void accessA(A& a) {// 友元类B可以访问A的私有成员和保护成员a.privateData = 10;a.protectedData = 20;}
};
注意:
- 友元关系是单向的
比如:类A声明类B为友元类,那么类B可以访问类A的私有成员和保护成员,但类A不能访问类B的私有成员和保护成员。
- 友元关系不能传递
如果C是B的友元, B是A的友元,则不能说明C时A的友元
- 友元关系不能继承
5. 内部类
什么是内部类?
一个类定义在另一个类的内部
内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限
比如:
class A
{
private:int h;
public:class B // B天生就是A的友元{public:void fun(const A& a){cout << a.h << endl;//OK}};
};
A于B的关系:
可以理解为B就是一个普通类,它只受A的类域和访问限定符限制,
int main()
{A aa;//B bb //error C2065: “B”: 未声明的标识符A::B bb;cout << sizeof(A) << endl; // 4return 0;
}
内部类天生就是外部类的友元
*6. 拷贝构造时的一些优化
在传参和传返回值的过程中,一般编译器会做一些优化,减少对象的拷贝。
比如:
class A
{
public:A(int a = 0):_a(a){cout << "A(int a)" << endl;}A(const A& aa):_a(aa._a){cout << "A(const A& aa)" << endl;}A& operator=(const A& aa){cout << "A& operator=(const A& aa)" << endl;if (this != &aa){_a = aa._a;}return *this;}~A(){cout << "~A()" << endl;}
private:int _a;
};int main()
{A aa1 = 1; return 0;
}
A aa1 = 1;
它的过程是什么样的?它的过程其实分为两步
1、先用1构造一个临时对象 2、再用临时对象拷贝构造aa1
但我们在调试时会发现最终编译器显示的是一次构造。这其实就是由于编译器的优化。
同一个表达式中,连续构造+构造 / 构造+拷贝构造 / 拷贝构造+拷贝构造 会合二为一
合并规则如下:
- 构造+构造->构造
- 构造+拷贝构造->构造
- 拷贝构造+拷贝构造->拷贝构造
编译器不同优化效果也不同,老的编译器不会怎么优化,但新的编译器基本都会做这样的优化,甚至优化的比这个更厉害。
总结
在C++编程中,掌握初始化列表、static成员、友元和内部类等相关知识是非常重要的。这些概念不仅能够帮助我们更好地理解C++语言的特性,还能够提高我们的编程效率和代码质量,以上便是本文全部内容,希望可以对你有所帮助,感谢阅读!
相关文章:
【C++入门】类和对象(完)
前言 在谈论C时,常常会涉及到一些高级特性和概念,比如初始化列表、static成员、友元、内部类、匿名对象等。这些概念在C编程中起着非常重要的作用,对于想要深入了解C语言的开发者来说,掌握这些知识是至关重要的。本文,…...
webshell检测方式深度剖析 --- Pixy系列二(数据流分析)
开篇 书接上文,这次我们来聊聊数据流分析,数据流分析的内容非常广泛,我们力求深入浅出通俗易懂,在简短的篇幅内将这一概念描述清楚。 简单来说,数据流分析是一种用来获取相关数据沿着程序执行路径流动的信息分析技术…...
[DAU-FI Net开源 | Dual Attention UNet+特征融合+Sobel和Canny等算子解决语义分割痛点]
文章目录 概要I Introduction小结 概要 提出的架构,双注意力U-Net与特征融合(DAU-FI Net),解决了语义分割中的挑战,特别是在多类不平衡数据集上,这些数据集具有有限的样本。DAU-FI Net 整合了多尺度空间-通…...
使用Triton部署ONNX模型
介绍 适用于各种 AI 工作负载的推理:借助 NVIDIA Triton™,在任何处理器(GPU、CPU 或其他)上,对使用基于任何框架的,经过训练的机器学习模型或深度学习模型,进行推理部署。Triton 是 NVIDIA AI…...
Python访问ElasticSearch
ElasticSearch是广受欢迎的NoSQL数据库,其分布式架构提供了极佳的数据空间的水平扩展能力,同时保障了数据的可靠性;反向索引技术使得数据检索和查询速度非常快。更多功能参见官网介绍 https://www.elastic.co/cn/elasticsearch/ 下面简单罗列…...
Flutter 混合开发 - 动态下发 libflutter.so libapp.so
背景 最近在做包体积优化,在完成代码混淆、压缩,裁剪ndk支持架构,以及资源压缩(如图片转webp、mp3压缩等)后发现安装包的中占比较大的仍是 so 动态库依赖。 具体查看发现 libflutter.so 和 libapp.so 的体积是最大的&…...
Peter算法小课堂—动态规划
Peter推荐算法书:《算法导论》 图示: 目录 钢条切割 打字怪人 钢条切割 算法导论(第四版)第十四章第一节:钢条切割 题目描述: 给定一根长度为 n 英寸的钢条和一个价格表 ,其中 i1,2,…,n …...
2022–2023学年2021级计算机科学与技术专业数据库原理 (A)卷
一、单项选择题(每小题1.5分,共30分) 1、构成E—R模型的三个基本要素是( B )。 A.实体、属性值、关系 B.实体、属性、联系 C.实体、实体集、联系 D.实体、实体…...
Clojure 实战(4):编写 Hadoop MapReduce 脚本
Hadoop简介 众所周知,我们已经进入了大数据时代,每天都有PB级的数据需要处理、分析,从中提取出有用的信息。Hadoop就是这一时代背景下的产物。它是Apache基金会下的开源项目,受Google两篇论文的启发,采用分布式的文件…...
Django 分页(表单)
目录 一、手动分页二、分页器分页 一、手动分页 1、概念 页码:很容易理解,就是一本书的页码每页数量:就是一本书中某一页中的内容(数据量,比如第二页有15行内容),这 15 就是该页的数据量 每一…...
socket实现视频通话-WebRTC
最近喜欢研究视频流,所以思考了双向通信socket,接下来我们就一起来看看本地如何实现双向视频通讯的功能吧~ 客户端获取视频流 首先思考如何获取视频流呢? 其实跟录音的功能差不多,都是查询电脑上是否有媒体设备,如果…...
simulink代码生成(九)—— 串口显示数据(纸飞机联合调试)
纸飞机里面的协议是固定的,必须按照协议配置; (1)使用EasyHEX协议,测试int16数据类型 测试串口发出的数据是否符合? 串口接收数据为: 打开纸飞机绘图侧: (1)…...
Mysql数据库(中)——增删改查的学习(全面,详细)
上一篇主要对查询操作进行了详细的总结,本篇主要对增删改操作以及一些常用的函数进行总结,包括流程控制等;以下的代码可以直接复制到数据库可视化软件中,便于理解和练习; 常用的操作: #函数: S…...
test dbtest-03-对比 Liquibase、flyway、dbDeploy、dbsetup
详细对比 Liquibase、flyway、dbDeploy、dbsetup,给出对比表格 下面是一个简要的对比表格,涵盖了 Liquibase、Flyway、dbDeploy 和 DbSetup 这四个数据库变更管理工具的一些主要特点。 特点/工具LiquibaseFlywaydbDeployDbSetup开发语言Java࿰…...
力导向图与矩阵排序
Graph-layout force directed(力导向图布局)是一种用于可视化网络图的布局算法。它基于物理模型,模拟了图中节点之间的相互排斥和连接弹性,以生成具有良好可读性和美观性的图形布局。 在力导向图布局中,每个节点被视为…...
word 常用功能记录
word手册 多行文字对齐标题调整文字间距打钩方框插入三线表插入参考文献自动生成目录 多行文字对齐 标题调整文字间距 打钩方框 插入三线表 插入一个最基本的表格把整个表格设置为无框线设置上框线【实线1.5磅】设置下框线【实线1.5磅】选中第一行,设置下框线【实线…...
C#线程基础(线程启动和停止)
目录 一、关于线程 二、示例 三、生成效果 一、关于线程 在使用多线程前要先引用命名空间System.Threading,引用命名空间后就可以在需要的地方方便地创建并使用线程。 创建线程对象的构造方法中使用了ThreadStart()委托,当线程开始执行时,…...
如何利用ChatGPT来提高编程效率
如何利用ChatGPT来提高编程效率 在当今这个信息爆炸和技术快速发展的时代,程序员们面临着巨大的压力,既要保证代码的质量,又要提高工作效率。幸运的是,人工智能(AI)正在改变我们编写和维护代码的方式,而OpenAI的ChatGPT是其中的佼佼者。本文将讨论如何利用ChatGPT以及结合…...
java智慧工地源码,互联网+建筑工地,实现对工程项目内人员、车辆、安全、设备、材料等的智能化管理
智慧工地全套源码,微服务JavaSpring Cloud UniApp MySql;支持多端展示(大屏端、PC端、手机端、平板端)演示自主版权。 智慧工地概念: 智慧工地就是互联网建筑工地,是将互联网的理念和技术引入建筑工地&…...
创建并使用自己的C++模块(Windows10+MSVC)
module是C20种新引入的特性,关于module的介绍和好处,网上已有大量的文章,此处也不再赘述,本文仅记录在个人的环境上创建一个简单的module并使用这个module。 环境同上一篇文章( windows10,MSVC C工具链&am…...
Spring Boot 2.7.11 集成 GraphQL
GraphQL介绍 GraphQL(Graph Query Language)是一种用于API的查询语言和运行时环境,由Facebook于2012年创建并在2015年公开发布。与传统的RESTful API相比,GraphQL提供了更灵活、高效和强大的数据查询和操作方式。 以下是GraphQL…...
软件工程期末总结
软件工程期末总结 软件危机出现的原因软件生命周期软件生命周期的概念生命周期的各个阶段 软件开发模型极限编程 可行性研究与项目开发计划需求分析结构化分析的方法结构化分析的图形工具软件设计的原则用户界面设计结构化软件设计面向对象面向对象建模 软件危机出现的原因 忽视…...
MidTool图文创作-GPT-4与DALL·E 3的结合
GPT-4与DALLE 3的结合 GPT-4是由OpenAI开发的最新一代语言预测模型,它在前代模型的基础上进行了大幅度的改进,不仅在文本生成的连贯性、准确性上有了显著提升,还在理解复杂语境和执行多步骤指令方面表现出了更高的能力。而DALLE 3则是一个创…...
Python将两个或多个列表合并为一个列表,并根据每个输入列表中的元素的位置将其组合在一起
将两个或多个列表合并为一个列表,并根据每个输入列表中的元素的位置将其组合在一起。 这个需求在实际开发过程中应该说非常常见,当然python也给我们内置了相关方法! zip(*iterables, strictFalse) 在多个迭代器上并行迭代,从每…...
数模混合SoC芯片中LEF2Milkyway的golden flow
在数模混合芯片中的项目中,特别是数字模块很少甚至只有一个简单的数字控制逻辑时,我们要做数字模块的后端实现时,通常模拟那边会问我们实现需要他们提供哪些数据。 通常来说,我们可以让模拟设计提供数字模块的GDS或LEF文件即可。…...
Five tips to make your essay flow
This post was written by Sydney Nicholson, a second-year master’s student in the English Department. Dear writer, Have you ever wondered what it takes to make an essay “flow”? In my time as a writing center tutor, I’ve noticed that this is one of th…...
linux驱动(二):led补
本文主要探讨s5pv210的led驱动相关知识,包括驱动主次设备注册和取消,udev(mdev)机制,静态和动态映射操作寄存器。 字符设备驱动注册 老接口(register_chrdev) static inline int register_chrdev(unsigned int major, const char *n…...
性能测试-jmeter:安装 / 基础使用
一、理解jmeter 官网-Apache JMeter-Apache JMeter™ JMeter是一款开源的性能测试工具,主要用于模拟大量用户并发访问目标服务器,以评估服务器的性能和稳定性。 JMeter可以执行以下任务序号用途描述1性能测试通过模拟多个用户在同一时间对服务器进行请…...
数据仓库-数仓优化小厂实践
一、背景 由于公司规模较小,大数据相关没有实现平台化,相关的架构都是原生的Apache组件,所以集群的维护和优化都需要人工的参与。根据自己的实践整理一些数仓相关的优化。 二、优化 1、简易架构图 2、ODS层优化 2.1 分段式解析 随着业务增长…...
uniapp中uview组件丰富的Code 验证码输入框的使用方法
目录 基本使用 #自定义提示语 #保持倒计时 API #Props #Methods #Event 基本使用 通过ref获取组件对象,再执行后面的操作,见下方示例。 通过seconds设置需要倒计的秒数(默认60)通过ref调用组件内部的start方法,开始倒计时通过监听cha…...
wordpress 文章编辑 插件/互联网推广广告
Akka 和 Storm 的设计差异 Akka 和 Storm 都是实现低延时, 高吞吐量计算的重要工具. 不过它们并非完全的竞品,如果说 Akka 是 linux 内核的话, storm 更像是类似 Ubuntu 的发行版.然而 Storm并非 Akka 的发行版, 或许说 Akka 比作 BSD, Storm 比作 Ubuntu 更合适. 实现的功能差…...
提供网站建设公司哪家好/百度权重
学习率的作用是控制更新的步伐; Pytorch提供了一个调整学习率的方法——class_LRScheduler 主要参数: optimizer:关联的优化器; last_epoch:记录epoch数; base_lrs:记录初始学习率class_LRSche…...
东莞创意网站设计/镇江网站定制
中文名称:鬼笔环肽(异硫氰酸荧光素标记) 英文名称:Phalloidin, Fluorescein Isothiocyanate Labeled 中文别名:鬼笔环肽-FITC 分子量:1252.44 分子式:C58H63N10O14S4 储存条件:…...
两学一做专题网站/百度高级搜索功能
点击上方"Java学习之道",选择"关注"公众号每天10:24,干货准时送达!本文经授权转载自公众号“吓脑湿”(imyourgrandpa) 互联网人,随时都得带手机和电脑。因为你永远都不知道——明天和工…...
wordpress+php允许上传文件大小/怎么给公司做网站
1、GUI偏重功能和页面测试,应使用工具如Selenium、QTP(UFT)来完成自动化测试。 Selenium简介: 1.0核心是Selenium RC,RC Server Client Lib组成,RCServer包括Launcher、Http Proxy、Selenium Core三个部…...
建设部指定招标网站/站长之家ip地址查询
上一篇ESFramework扩展之EsfP2P -- 基于ESFramework的P2P实现 主要介绍了EsfP2P如何协助建立P2P Session,那只是整个故事的一半,EsfP2P主要职能的另一半是确保P2P消息的可靠传递。我们已经知道,目前的EsfP2P扩展的实现…...