类和对象(三)
目录
一. 构造函数初始化列表
二. 类型转换
三. static成员
四. 友元
五. 内部类
六. 匿名对象
七. 对象拷贝时的编译器优化
一. 构造函数初始化列表
1. 之前我们实现构造函数时,初始化成员变量主要使用函数体内赋值,构造函数初始化还有一种方式,就是初始化列表,初始化列表的使用方式是以一个冒号开始,接一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。
2. 每个成员变量在初始化列表中只能出现一次,语法理解上初始化列表可以认为是每个成员变量定义初始化的地方。
3. 引用成员变量,const成员变量,没有默认构造的类类型变量,必须放在初始化列表位置进行初始化,否则会编译报错
#include<iostream>
using namespace std;class jubge
{
public:jubge(int tmp = 0):_tmp(tmp){cout << " 叮叮叮 " << endl;}int val(){return _tmp;}
private:int _tmp;
};
class Pc
{
public:Pc(int& x, int a = 1, int b = 21, int c = 11):_a(a), _b(b), _c(c), _s(33), _t(x), j(333)//, _b(b)每种成员变量只能在初始化列表出现一次{}void Printf(){cout << _a << " " << _b << " " << _c << " " << _t << " "<<j.val() << " " << _s << endl;}
private:int _a;int _b;int _c;int& _t;jubge j;const int _s;
};int main()
{int v = 10;int& x = v;Pc p(x);p.Printf();
}
而上文的引用必须初始化,const必须在初始化时赋值,类没有默认构造只能传参赋值
它们不能在函数体内赋值,引用必须初始化然后不能改变指向,const需要设置初始值后不能改变,类也需要参数初始化,没有其他函数使其改变
4. C++11支持在成员变量声明的位置给缺省值,这个缺省值主要是给没有显示在初始化列表初始化的成员使用的
5. 尽量使用初始化列表初始化,因为那些你不在初始化列表初始化的成员也会走初始化列表,如果这个成员在声明位置给了这个缺省值,初始化列表会用这个缺省值初始化。如果你没有给缺省值,对于没有显示在初始化列表初始化的内置类型成员是否初始化取决于编译器,C++没规定。而对没显示在初始化列表的自定义类型成员会调用这个成员类型的默认构造函数,如果没有默认构造会编译错误
6. 初始化列表中按照成员变量在类中声明顺序进行初始化,跟成员在初始化列表出现的先后顺序无关。建议声明顺序和初始化列表顺序保持一致
#include<iostream>
using namespace std;class jubge
{
public:jubge(int tmp = 0):_tmp(tmp){cout << " 叮叮叮 " << endl;}int val(){return _tmp;}
private:int _tmp;
};
class Pc
{
public:Pc(int& x): _t(x){}void Printf(){cout << _a << " " << _b << " " << _c << " " << _t << " "<<j.val() << " " << _s << endl;}
private:int _a=1;int _b=21;int _c=11;int& _t;jubge j=333;const int _s=33;int* p = (int*)malloc(12);
};int main()
{int v = 10;int& x = v;Pc p(x);p.Printf();
}
我们发现我们没在初始化列表里定义,但是依然会根据初始化
我们可以思考一下以下代码指向结果为
#include<iostream>
using namespace std;
class Pc
{
public:Pc(int a):_a(a), _b(_a){}void Printf(){cout << _a << " " << _b << " "<< endl;}
private:int _b = 21;int _a = 1;
};int main()
{Pc p(10);p.Printf();
}
由于初始化列表按照成员变量在类中的声明顺序进行初始化。跟成员在初始化列表中出现的顺序无关。所以会导致先初始化_b再初始化_a,用于初始化_b的_a是随机值,然后初始化_a为10
答案为 10 随机值
二. 类型转换
1. C++支持内置类型隐式转换为类类型对象,需要有相关内置类型为参数的构造函数
2. 构造函数前面加explicit 就不再支持隐式类型转换
#include<iostream>
using namespace std;
class Pc
{
public:Pc(int a):_a(a), _b(a){}Pc(int a,int b):_a(a), _b(b){}void Printf() const{cout << _a << " " << _b << " "<< endl;}
private:int _b = 21;int _a = 1;
};int main()
{Pc p = 10;p.Printf();//Pc& pp = 1;const Pc& pp = 1;//产生的临时对象具有常性pp.Printf();//C++11后才支持多参数转化Pc ppp = { 3,3 };ppp.Printf();
}
第一个赋值,1构造一个Pc的临时对象,再用这个临时对象拷贝构造p,编译器遇见连续构造+拷贝构造
如果将类改为以下代码
class Pc
{
public:explicit Pc(int a):_a(a), _b(a){}explicit Pc(int a,int b):_a(a), _b(b){}void Printf() const{cout << _a << " " << _b << " "<< endl;}
private:int _b = 21;int _a = 1;};
就不再支持隐式类型转换了
三. static成员
1. 用static修饰的成员变量,称之为静态成员变量,静态成员变量一定要在类外进行初始化。
2. 静态成员变量为所有类对象所共享,不属于某个具体的对象,不存在对象中,存放在静态区中。
3. 用static修饰的成员函数,称之为静态成员函数,静态成员函数没有this指针。
4. 静态成员函数可以访问其他静态成员但不能访问非静态的,因为没有this指针。
5. 非静态的成员函数,可以访问任意的静态成员变量和静态成员函数。
6. 突破类域就可以访问静态成员,可以通过类名::静态成员或对象.静态成员来访问来访问静态成员变量和静态成员函数
7. 静态成员变量不能在声明位置给缺省值初始化,因为缺省值是个构造函数初始化列表的,静态成员变量不属于某个对象,不走构造函数初始化列表
#include<iostream>
using namespace std;
class Pc
{
public:Pc():_a(1), _b(1){}static int GetVal(){//_b=0;//没有this指针无法访问return n;}void PrintfStatic(){cout << c << " " << GetVal() << " " << n << endl;}void Printf() const{cout << _a << " " << _b << " " << endl;}static int c;
private:int _b = 21;int _a = 1;static int n;};
int Pc:: c = 10;
int Pc::n = 111;
int main()
{Pc::c = 1;cout << Pc::c << endl;Pc p;cout << p.c << endl;p.PrintfStatic();
}
四. 友元
1. 友元提供了⼀种突破类访问限定符封装的⽅式,友元分为:友元函数和友元类,在函数声明或者类 声明的前⾯加friend,并且把友元声明放到⼀个类的⾥⾯。
2. 外部友元函数可访问类的私有和保护成员,友元函数仅仅是⼀种声明,他不是类的成员函数。
3. 友元函数可以在类定义的任何地⽅声明,不受类访问限定符限制。
4. ⼀个函数可以是多个类的友元函数。
如以下代码所示
#include<iostream>
using namespace std;class Pc;class AAA
{public:AAA():_t(10), _s(1){}
private:friend void Printf(const Pc& p, const AAA& a);//声明可以在任何地方int _t;int _s;
};class Pc
{friend void Printf(const Pc& p,const AAA& a);public:Pc():_a(1), _b(1){}
private:int _b = 21;int _a = 1;
};void Printf(const Pc& p, const AAA& a)
{cout << p._a << " " << p._b << " " << endl;cout << a._s << " " << a._t << " " << endl;
}
int main()
{Pc p;AAA a;Printf(p,a);
}
5. 友元类中的成员函数都可以是另⼀个类的友元函数,都可以访问另⼀个类中的私有和保护成员。
6. 友元类的关系是单向的,不具有交换性,比如A类是B类的友元,但是B类不是A类的友元。
7. 友元类关系不能传递,如果A是B的友元,B是C的友元,但是A不是C的友元。
8. 有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多⽤。
#include<iostream>
using namespace std;class Pc;
class BBB;
class AAA
{friend class Pc;
public:AAA():_t(10), _s(1){}//void PirntfPc(const Pc& p,const BBB& b)//{// cout << p._b << " " << p._s << endl;//友元关系是单向的// cout << b.n << endl;//友元的关系不可传递//}
private:int _t;int _s;
};
class BBB
{private:int n = 0;};class Pc
{friend class BBB;
public:Pc():_a(1), _b(1){}void PirntfAAA(const AAA& a){cout << a._t << " " << a._s << endl;}private:int _b = 21;int _a = 1;
};
int main()
{Pc p;AAA a;p.PirntfAAA(a);
}
五. 内部类
1. 如果一个类定义在另一个类的内部,这个类就叫做内部类。内部类是一个独立的类,跟定义在全局相比,他只是受外部类类域限制和访问限定符限制,所以外部类定义的对象中不包含内部类
2. 内部类默认为外部类的友元类
3. 内部类本质也是一种封装,当A类与B类紧密相关,A类的实现就是为了给B类使用的时候,可以考虑把A类设计为B的内部类,如果放到protected/private位置,那A类就是B类的专属内部类,其他地方都用不了
#include<iostream>
using namespace std;class Pc
{public:Pc():_a(1), _b(1){}void printfAAAPc(){AAA a;a.PirntfPc(*this);a.PrintfAAA();}class BBB{public:void PirntfPc(const Pc& p){cout << "BBB" << endl;cout << p._b << " " << p._a << endl;}};
private:class AAA{public:AAA():_t(10), _s(1){}void PrintfAAA(){cout << _t << " " << _s << endl;}void PirntfPc(const Pc& p){cout << "AAA" << endl;cout << p._b << " " << p._a << endl;}private:int _t;int _s;};int _b = 21;int _a = 1;
};
int main()
{Pc p;Pc::BBB b;b.PirntfPc(p);p.printfAAAPc();
}
六. 匿名对象
用 类型(实参) 定义出来的对象叫做匿名对象,相⽐之前我们定义的 类型对象名(实参) 定义出来的 叫有名对象
匿名对象⽣命周期只在当前⼀行,⼀般临时定义⼀个对象当前用⼀下即可,就可以定义匿名对象。
以下代码可以验证
#include<iostream>
using namespace std;class Pc
{public:Pc():_a(1), _b(1),_val(111){cout << "构造了" << endl;}~Pc(){cout << "析构了" << endl;}int GetVal(){return _val;}
private:int _b ;int _a = 1;int _val = 111;
};
int main()
{Pc();cout << Pc().GetVal() << endl;return 0;
}
七. 对象拷贝时的编译器优化
现代编译器,会为了尽可能的提高程序效率,在不影响正确性的情况下会尽可能减少一些传参和传参过程中可以省略的拷贝。
如何优化C++标准没有严格规定,各个编译器会根据情况自行处理。当前主流的相对新的编译器对于连续一个表达式步骤中的连续拷贝会进行合并优化,有些更新更‘激进’的编译还会进行跨行跨表达式的合并优化
如以下代码:
#include<iostream>
using namespace std;class AAA
{
public:AAA(int a){_a = a;cout << "构造" << endl;}AAA(const AAA& a){_a = a._a;cout << "拷贝构造" << endl;}void operator=(const AAA& a){_a = a._a;cout << "重载赋值" << endl;}void Printf(){cout << "printf->" << _a << endl;}~AAA(){cout << "析构" << endl;}
private:int _a;
};AAA f()
{AAA a(1);return a;
}int main()
{AAA aaa(1);aaa = f();aaa.Printf();cout << "*********" << endl;return 0;
}
按理来说会 1. 将 aaa 执行构造函数 2. 进入 f 函数后 对a执行构造函数 ,3. 将a拷贝构造赋值给临时对象,4. 将a 析构 5. 执行函数重载=,6. 再将临时对象 析构 ,7. 再执行 aaa的Printf函数, 8. 执行cout 9. 将aaa 析构
而在vs2019中Debug下也是这么做的,但在vs2022的激进优化下变为了 1. 将aaa执行构造函数,2. 进入f 函数后对a 进行构造函数 3. 将a 赋值给 aaa,4. 将 a 析构 5.执行 aaa的Printf函数 6. 执行cout 7. 将aaa 析构
结果如下
这篇先写到这里,明天补第七条,喜欢可以点一下赞
(๑′ᴗ‵๑)I Lᵒᵛᵉᵧₒᵤ❤
相关文章:

类和对象(三)
目录 一. 构造函数初始化列表 二. 类型转换 三. static成员 四. 友元 五. 内部类 六. 匿名对象 七. 对象拷贝时的编译器优化 一. 构造函数初始化列表 1. 之前我们实现构造函数时,初始化成员变量主要使用函数体内赋值,构造函数初始化还有一种方式&…...

Android SurfaceFlinger——GraphicBuffer初始化(二十九)
在 SurfaceFlinger 中,GraphicBuffer 是一个关键的数据结构,用于封装和管理图形数据的内存缓冲区。它不仅在 SurfaceFlinger 内部使用,也被其他组件如 GPU 驱动、摄像头服务、视频解码器等广泛利用,以实现高效的数据交换和图形渲染。 一、概述 GraphicBuffer 对象封装了一…...

pytest:4种方法实现 - 重复执行用例 - 展示迭代次数
简介:在软件测试中,我们经常需要重复执行测试用例,以确保代码的稳定性和可靠性。在本文中,我们将介绍四种方法来实现重复执行测试用例,并显示当前迭代次数和剩余执行次数。这些方法将帮助你更好地追踪测试执行过程&…...

一文入门SpringSecurity 5
目录 提示 Apache Shiro和Spring Security 认证和授权 RBAC Demo 环境 Controller 引入Spring Security 初探Security原理 认证授权图示编辑 图中涉及的类和接口 流程总结 提示 Spring Security源码的接口名和方法名都很长,看源码的时候要见名知意&am…...

IPython的HTML魔法:%%html_header命令全解析
IPython的HTML魔法:%%html_header命令全解析 在IPython和Jupyter Notebook中,%%html_header是一个魔术命令,它允许用户在Notebook的单元格中添加HTML头部(head)内容。这个功能特别有用,当你需要定制Notebo…...

将SQL中的占位符替换成参数
将SQL中的占位符替换成参数 描述 描述 此方法是将SQL中的${}或#{}替换为直接拼接到SQL中或直接替换为?的形式。具体详情看下面代码。 import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern;/*** author HuYu* date 2023-09-21* since 1.0**…...

锁相环 vivado FPGA
原理 同步状态/跟踪状态:相位差在2kπ附近,频率差为0到达上述状态的过程称为捕获过程锁相环的捕获带:delta w的最大值,大于这个值的话就不能捕获鉴相器(PD-phase discriminator):相乘加LPF&…...

英语科技写作 希拉里·格拉斯曼-蒂(英文版)pdf下载
下载链接: 链接1:https://pan.baidu.com 链接2:/s/1fxRUGnlJrKEzQVF6k1GmBA 提取码:b69t 由于是英文版,可能有些看着不太方便,可以在网页版使用以下软件中英文对照着看,看着更舒服,…...

《Dynamic Statistical Learning in Massive Datastreams》论文阅读笔记
论文地址: https://www3.stat.sinica.edu.tw/ss_newpaper/SS-2023-0195_na.pdf 论文题目翻译:《在大规模数据流中的动态统计学习》 核心观点: 动态跟踪和筛选框架(DTS):论文提出了一个在线学习和模型更新的新框架&…...

【数据分享】2008-2022年我国省市县三级的逐日NO2数据(excel\shp格式)
空气质量数据是在我们日常研究中经常使用的数据!之前我们给大家分享了2000-2022年的省市县三级的逐日PM2.5数据、2013-2022年的省市县三级的逐日CO数据和2013-2022年的省市县三级的逐日SO2数据(均可查看之前的文章获悉详情)! 本次…...

JavaEE (1)
web开发概述 所谓web开发,指的是从网页中向后端程序发送请求,与后端程序进行 交互. 流程图如下 Web服务器是指驻留于因特网上某种类型计算机的程序. 可以向浏览器等Web客户端提供文档,也可以放置网站文件,让全世界浏览; 它是一个容器&…...

事务、函数和索引
什么是事务? 事务(Transaction),就是将一组SQL语句放在同一批次内去执行,如果一个SQL语句出错,则该批次内 的所有SQL都将被取消执行。 特点 一个事务中如果有一个数据库操作失败,那么整个事务…...

Android APP 基于RecyclerView框架工程(知识体系积累)
说明:这个简单的基于RecyclerView的框架作用在于自己可以将平时积累的一些有效demo整合起来(比如音视频编解码的、opengles的以及其他也去方向的、随着项目增多,工程量的增加,后期想高效的分析和查找并不容易)…...

【iOS】GCD
参考文章:GCD函数和队列原理探索 之前写项目的时候,进行耗时的网络请求使用GCD处理过异步请求,但对一些概念都很模糊,这次就来系统学习一下GCD相关 相关概念 什么是GCD? Grand Center Dispatch简称GCD,是…...

C语言 | Leetcode C语言题解之第282题给表达式添加运算符
题目: 题解: #define MAX_COUNT 10000 // 解的个数足够大 #define NUM_COUNT 100 // 操作数的个数足够大 long long num[NUM_COUNT] {0};long long calc(char *a) { // 计算表达式a的值// 将数字和符号,入栈memset(num, 0, sizeof(num));in…...

如何使用 API list 极狐GitLab 容器镜像仓库中的 tag?
GitLab 是一个全球知名的一体化 DevOps 平台,很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab :https://gitlab.cn/install?channelcontent&utm_sourcecsdn 是 GitLab 在中国的发行版,专门为中国程序员服务。可以一键式部署…...

粒子群算法PSO优化BP神经网络(PSO-BP)回归预测——Python和MATLAB实现
下面是一个使用Python实现的粒子群算法(PSO)优化反向传播神经网络(BP)的示例代码。 以下是具体的代码实现: python import numpy as np from sklearn.datasets import make_regression from sklearn.model_selection…...

React-router路由配置及跳转
1、V6对比V5的修改内容 1、API: useNavigate 代替了useHistory 。 2、废弃了Route组件的exact属性。 3、组件 <Routes>代替了<Switch> 4、组件NavLink中移除了 activeStyle activeClassName 属性。 2、安装依赖react-router-dom npm install react-router-dom…...

vue3【实战】可编辑的脱敏信息
<script lang"ts" setup> import { ref, onMounted } from "vue"; let real_name ref("朝阳");let name ref("");onMounted(() > {name.value des_name(real_name.value); });function focusing() {name.value real_name…...

S71200 - 笔记
1 S71200 0 ProfiNet - 2 PLC编程 01.如何零基础快速上手S7-1200_哔哩哔哩_bilibili 西门子S7-1200PLC编程设计学习视频,从入门开始讲解_哔哩哔哩_bilibili...

linux系统查历史cpu使用数据(使用sar 查询cpu和网络占用最近1个月历史数据)。
一 sar 指令介绍 在 Linux 系统中,sar 是 System Activity Reporter 的缩写,是一个用于收集、报告和保存系统活动信息的工具。它是 sysstat 软件包的一部分,提供了丰富的系统性能数据,包括 CPU、内存、网络、磁盘等使用情况&am…...

Edge浏览器加载ActiveX控件
背景介绍 新版Edge浏览器也是采用Chromium内核,虽然没有谷歌浏览器市场占有率高,但是依托微软操作系统的优势,Edge浏览器还是发展很强劲,占据着市场第二的位置。随着微软停止服务IE浏览器,曾经风光无限的IE浏览器页退出…...

BUG与测试用例设计
一.软件测试的生命周期 需求分析→测试计划→测试设计,测试开发→测试执行→测试评估→上线→运行维护 二.BUG 1.bug的概念 (1)当且仅当规格说明(需求文档)是存在的并且正确,程序与规格说明之间的不匹配才是错误. (2)当需求规格说明书没有提到的功能,判断标准以最终用户为准…...

怎么在使用select2时,覆盖layui的下拉框样式
目录 1.覆盖下拉框样式代码 2.自定义样式 3.样式使用 1.覆盖下拉框样式代码 .layui-form-select .layui-select-title {border: none !important; /* 去除边框 */background-color: transparent !important; /* 去除背景色 */display: none;/* 其他你想要覆盖的样式 */} 2.自…...

MacOSM1 配置Miniconda环境,并设置自启动
文章目录 设置环境变量设置自启动参考 设置环境变量 cd vim .zshrc输入一下内容 # 配置Conda CONDA_HOME/Users/hanliqiang/miniconda3 PATH$CONDA_HOME/bin:$PATH生效配置 source .zshrc设置自启动 conda init zsh.zshrc 文件中将会出现以下内容 # >>> conda i…...

poi库简单使用(java如何实现动态替换模板Word内容)
目录 Blue留言: Blue的推荐: 什么是poi库? 实现动态替换 第一步:依赖 第二步:实现word模板中替换文字 模板word: 通过以下代码:(自己建一个类,随意取名…...

机器人开源调度系统OpenTcs6二开-车辆表定义
前面已经知道opentcs 需要车辆的模型结构数据,将里面的数据结构化,已表的形式生成,再找一个开源的基础框架项目对车辆进行增删改的管理 表结构: CREATE TABLE Vehicle (id INT AUTO_INCREMENT PRIMARY KEY COMMENT 唯一标识符,n…...

麦歌恩MT6521-第三代汽车磁性角度传感器芯片
磁性编码芯片 -在线编程角度位置IC 描述: MT6521是麦歌恩微电子推出的新一代基于水平霍尔及聚磁片(IMC)技术原理的磁性角度和位置检测传感器芯片。该芯片内部包含了两对互成90放置的水平霍尔阵列及聚磁片,能够根据不同的型号配置来实现对XY࿰…...

【数据结构】堆,优先级队列
目录 堆堆的性质大根堆的模拟实现接口实现构造方法建堆入堆判满删除判空获取堆顶元素 Java中的PriorityQueue实现的接口构造方法常用方法PriorityQueue注意事项 练习 堆 如果有一个集合K {k0,k1, k2,…,kn-1},把它的…...

2024 暑假友谊赛 2
Tree Queries - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 思路:LCA好题,也有看见用时间戳写的,不是很明白. 用LCA非常好写。 要想到,给出k个节点,要确定一条路径,使得给出的k个点要么在路径上,要么和路径中某点的…...