C++初阶 | [四] 类和对象(下)

摘要:初始化列表,explicit关键字,匿名对象,static成员,友元,内部类,编译器优化

类是对某一类实体(对象)来进行描述的,描述该对象具有哪些属性、哪些方法,描述完成后就形成了一种新的自定义类型,才用该自定义类型就可以实例化具体的对象。


1. 初始化列表

构造函数函数体内是对成员变量进行赋值,而不是初始化!

初始化列表:成员变量定义的地方

为什么规定初始化列表是所有成员变量定义的地方?

对于以下三类特殊的成员变量类型,初始化列表的存在是必要的:

  • const 成员变量—— const 变量必须在定义时初始化
  • 引用 —— 引用必须初始化
  • 自己没有默认构造函数自定义类型变量

warning:Initialization is not assignment. Initialization happens when a variable is given a value when it is created. Assignement obliterates an object's current value and replaces that value with a new one.

 Four different ways  to define an int variable named units_sold and initialize it to 0:

  • int units_sold = 0;
  • int units_sold = {0}; //list initialization (C++11)
  • int units_solc{ 0 }; //list initialization (C++11)
  • int units_sold(0);

——《C++ Primer》

Use

  1. 冒号开始,逗号分隔,初始化值/表达式 用括号括起来。示例如下。
  2. 成员变量走初始化列表的顺序为成员变量声明的顺序.(如下图,先用v2初始化v1,而v2还未初始化所存储的为随机值)
  3. C++规定初始化列表是每个成员变量定义的地方,每个成员变量会走初始化列表(所以成员变量的初始化尽量使用初始化列表),定义的时候不给初始值——即在初始化列表没有显式写的成员变量——未被初始化。
  4. 在初始化列表没写的成员变量,对于内置类型将不做处理——初始化值为随机值(但因编译器不同而异),对于自定义类型默认调用它自己的构造函数

sum.能用初始化列表就用初始化列表,但同时有些场景需要初始化列表和构造函数体混用。(根据具体的需求而异)

补充:C++11 支持在成员变量声明的时候给缺省值,这个缺省值是给初始化列表用的,如果初始化列表没有显式给初始值,就用缺省值作为初始化值。


2. explicit 关键字

  • C++98 支持单参数隐式类型转化

  • C++11 进一步支持多参数隐式类型转化

 在构造函数前加 explicit 使得不能进行隐式类型转换:(示例如下)

class B
{
public:explicit B(const int b1, const int b2){_b1 = b1;_b2 = b2;}explicit B(const B& b){_b1 = b._b1;_b2 = b._b2;}
private:int _b1;int _b2;
};

3. 匿名对象

  • 匿名对象:生命周期仅在改匿名对象定义的这一行。e.g.A(7);
  • 有名对象:生命周期在该作用域。e.g.A aa(7);

用途:

  1. 传参(如果单/多参数隐式类型转化被禁)
  2. 定义对象就是为了调用成员函数 → 就可以用匿名对象去调用
  3. ……(匿名对象的用途是十分广泛的)

const引用会延长匿名对象的生命周期

const引用其实使得匿名对象变成了有名对象:引用给了匿名对象别名,这个“别名”的生命周期即为被引用的匿名对象的生命周期。e.g.const A& ref = A();


4. static 成员

如果我们有如下两个需求:

  • 统计累计创建了多少个对象
  • 统计正在使用的对象还有多少个

统计累计创建的对象:首先,我们可以选择创建全局变量来统计。同时,因为创建对象会自动调用构造函数,所以我们在构造函数体内对这个用于统计的变量进行++操作,这样每次创建一个对象,就会调用并执行构造函数,每次执行都会累计对这个全局变量++。

统计正在使用的对象:对象销毁会自动调用析构函数,创建的对象 - 已经析构的对象 = 正在使用的对象。

int e = 0;//统计累计创建的对象
int now_e = 0;//统计仍在使用的对象class A
{
public:A(const int a = 0){++e;++now_e;_a = a;}~A(){--now_e;}
private:int _a;
};

问题:不够封装,全局变量可能会被随意修改,将造成需求之外的影响。 → “封装” → 将变量放入类中  →  私有变量无法访问 → static 成员

static 成员变量

static 成员变量的性质:

  1. 属于所有对象——即整个类,而不是某一个对象。
  2. 不能给缺省值。
  3. 不走初始化列表,初始化列表是某个对象的初始化,而 static 成员变量不属于某个对象。
  4. 位于静态区。

static 成员变量的声明与定义:类内声明,类外定义(静态成员变量一定要在类外进行初始化)

class A
{
private:static int m;//static成员变量声明
};//这样写A相当于空类int A::m = 0;//static成员变量定义

访问 static 成员变量的两种情况下的方式:

  • 如果 static 成员变量是 public 的:①创建对象访问;②通过指针访问(这里的指针只是为了突破类域,而不会解引用,之前在类和对象上的this指针关于空指针的内容有详细解释);③直接访问。
    class A
    {
    public:static int m;//static成员变量声明
    };//这样写A相当于空类int A::m = 0;//static成员变量定义int main()
    {A aa;aa.m;//①创建对象访问;A* p = nullptr;p->m;//②通过指针访问A::m = 1;//③直接访问return 0;
    }
    
  • 如果 static 成员变量是 非public 的:提供函数接口访问,这样可以使得 static 成员变量是只读不可修改的(引用返回可修改,这个根据需求自己控制),不同于public的情况。
    class A
    {
    public:int GetM(){return m;}
    private:static int m;//static成员变量声明
    };int A::m = 0;//static成员变量定义int main()
    {A aa;cout << aa.GetM() << endl;return 0;
    }

static 成员函数

static 成员函数的性质:

  1. 没有 this 指针,不能访问非静态成员变量
  2. 访问方式同 static 成员变量——突破类域即可访问 

5. 友元

  • 友元函数

特性:

  1. 可以访问类的 private 和protected 的成员,但友元函数不是类的成员函数。
  2. 不能用 const 修饰(因为不是成员函数更没有 this 指针,const 修饰的是 this 指针)。
  3. 可在类定义的任何地方声明,不受访问限定符限制。
  4. 一个函数可以是多个类的友元函数。
  5. 友元函数的调用同普通函数
class Date
{friend ostream& operator<<(ostream& out, Date d);//友元函数声明private:int _year;int _month;int _day;
};ostream& operator<<(ostream& out, Date d)//函数定义
{out << d._year << "/" << d._month << "/" << d._day << endl;return out;
}

  • 友元类

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。(如下代码,B类在A类友元声明之后,B类中的所有成员函数相当于在A类中都进行了友元声明——可以访问A类的非公有成员。注意:A类不可以访问B类的非公有成员。)

友元类的性质:

①单向性(如下,B可以访问A,但A不可以访问B);

②友元关系不传递(B是A的友元,A是C的友元,不能得出B是C的友元);

③不继承。

class A
{friend class B;private:int _a;
};class B
{void Print(A _aa){cout<<_aa._a;}//A aa;//注意:这个只是声明,不开空间
};

6. 内部类

内部类:在类中再定义一个类。内部类受外部类的类域和访问限定符限制,此外内部类与外部类是两个独立的类。

使用场景:内部类可以应用于当你想定义一个类而仅在某个类中使用时。

注意:如上图,C不可以访问D的非公有成员, D在C类域之内又封装了一层,并且根据友元类的单向性也是如此。


7. 拷贝对象时编译器的一些优化

此部分内容仅作了解,在之前旧版本的博客有较为详细的讲述,详细内容可参见本文:C++ -4- 类和对象(下)


END

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

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

相关文章

HarmonyOS ArkTS语言,运行Hello World(二)

一、认识DevEco Studio界面 进入IDE后&#xff0c;我们首先了解一下基础的界面。整个IDE的界面大致上可以分为四个部分&#xff0c;分别是代码编辑区、通知栏、工程目录区以及预览区。 代码编辑区 1、中间的是代码编辑区&#xff0c;你可以在这里修改你的代码&#xff0c;以…

安装oracle19c卡在安装界面

我在个人window10电脑上安装 Oracle 19c 时遇到问题。解压后的数据库文件放在没有中文的文件目录下面&#xff0c;用管理员用户启动 CMD 窗口进行安装&#xff0c;但随后卡在菜单上。 取消安装之后去任务管理器中的服务里停掉OracleRemExecServiceV2服务。 用管理员运行CMD…

51单片机直流电机控制

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pwm波形&#xff1f;1.1高低电平交互&#xff0c;LED亮灭。1.2 驱动电机时&#xff1f;1.3 怎么调节电机的速度&#xff1f; 二、怎么用51单片机产生PWM波形…

深度学习系列53:mmdetection上手

1. 安装 使用openmim安装&#xff1a; pip install -U openmim mim install "mmengine>0.7.0" mim install "mmcv>2.0.0rc4"2. 测试案例 下载代码和模型&#xff1a; git clone https://github.com/open-mmlab/mmdetection.git mkdir ./checkpoi…

(二)汇编语句组成

一个完整的 RISC-V 汇编程序有多条 语句&#xff08;statement&#xff09; 组成。 一条典型的 RISC-V 汇编 语句 由 3 部分组成&#xff1a; 1.标签 List item label&#xff08;标签&#xff09;: 标签是标识程序位置的记号。通常定义一个名称然后加上":"后缀。…

2023初中生古诗文大会复赛12月2日举行,来做做全真在线模拟题吧

2023年11月19日日&#xff0c;上海市古诗文大会主办方通过官微发布了2023上海中学生古诗文大会&#xff08;初中组&#xff09;复选将于12月2日举行的通知&#xff0c;就初中生古诗文大会复赛&#xff08;复选&#xff09;的相关安排做了说明&#xff0c;六分成长已经为您把通知…

CSDN的文档编辑器使用

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

越南MIC新规针对ICT和ITE产品电气授权标准变更

从2024年1月1日起&#xff0c;所有ICT和ITE产品(如台式电脑、笔记本电脑、平板电脑、DVB-T2电视/机顶盒、DECT电话等)都需要越南MIC授权的电气安全标准——QCVN132:2022。 目前MIC仍未最终确定要求&#xff0c;因为这与另一个监管机构存在冲突。所以目前他们可以接受ISO 17025的…

竞赛选题 深度学习验证码识别 - 机器视觉 python opencv

文章目录 0 前言1 项目简介2 验证码识别步骤2.1 灰度处理&二值化2.2 去除边框2.3 图像降噪2.4 字符切割2.5 识别 3 基于tensorflow的验证码识别3.1 数据集3.2 基于tf的神经网络训练代码 4 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x…

macOS下如何使用Flask进行开发

&#x1f468;&#x1f3fb;‍&#x1f4bb; 热爱摄影的程序员 &#x1f468;&#x1f3fb;‍&#x1f3a8; 喜欢编码的设计师 &#x1f9d5;&#x1f3fb; 擅长设计的剪辑师 &#x1f9d1;&#x1f3fb;‍&#x1f3eb; 一位高冷无情的编码爱好者 大家好&#xff0c;我是全栈工…

Cannot find proj.db

原因 编译GDAL完成后&#xff0c;我打了个包(包括.so)移动到了另外同环境的机器上。 应用gdal ogr2ogr时候提示找不到proj.db 解决办法&#xff1a; 把proj的share拷贝到另外环境上。 #gdal新建othershare&#xff0c;proj的share复制过去 mkdir -p /usr/local/gdal-3.6.2…

字符串函数详解

一.字母大小写转换函数. 1.1.tolower 结合cppreference.com 有以下结论&#xff1a; 1.头文件为#include <ctype.h> 2.使用规则为 #include <stdio.h> #include <ctype.h> int main() {char ch A;printf("%c\n",tolower(ch));//大写转换为小…

打印工具HandyPrint Pro Mac中文版软件特点

HandyPrint Pro Mac是一款打印工具&#xff0c;它支持AIrPrint协议&#xff0c;可以让用户在iPhone、iPad、iPod等设备上进行打印操作&#xff0c;只需要将这些设备连接到Mac电脑的WiFi网络中即可实现打印功能。 ​ HandyPrint Pro Mac软件特点 简单易用&#xff1a;用户只需…

基于单片机PM2.5监测系统仿真设计

**单片机设计介绍&#xff0c; 基于单片机PM2.5监测系统仿真设计 文章目录 一 概要简介设计目标系统组成工作流程仿真设计结论 二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 # 基于单片机PM2.5监测系统仿真设计介绍 简介 PM2.5&#xff08;可吸…

QQ自动批量加好友(手机端)

1.需求 按照格式输入批量qq号,输入加好友间隔时间,脚本自动打开qq应用开始自动加好友,全程自动化操作。 输入qq号格式: 运行示意图: 2.代码 function carmiLogin () {var carmi = getCarMi()try {const data = {"key": carmi}http.__okhttp__.setTimeout(3000…

大势智慧代理商体系持续开疆拓土,全国代理火热招募中...

11月15日&#xff0c;武汉大势智慧科技有限公司&#xff08;后简称“大势智慧”&#xff09;与上海宝天信息科技有限公司&#xff08;后简称“宝天信息”&#xff09;金牌代理商签约授牌仪式成功举行。大势智慧副总裁周济安先生、宝天信息经理王芳女士分别作为双方签约代表出席…

【WSL/WSL2-Ubuntu】突破界限:不使用服务器在一台Windows搭建Nginx+FastDFS

打造超级开发环境&#xff1a;Nginx和FastDFS在WSL中的完美结合 前言 随着软件开发领域的快速发展&#xff0c;跨平台的开发环境变得日益重要。Windows Subsystem for Linux&#xff08;WSL&#xff09;和WSL 2为开发者提供了在Windows操作系统上体验Linux环境的便捷途径。本…

解决IP查询结果偏差的几个方法

解决IP查询结果偏差的方法可以包括以下几个方面&#xff1a; 选择权威的IP查询工具&#xff1a;使用来自可信来源的IP查询工具&#xff0c;例如官方或专业的IP地址数据库&#xff0c;以确保查询结果的准确性和可靠性。 考虑使用代理服务器或VPN&#xff1a;如果需要更准确的IP…

CentOS7 安装mysql8(离线安装)postgresql14(在线安装)

注&#xff1a;linux系统为vmware虚拟机&#xff0c;和真实工作环境可能有出入&#xff0c;不过正因如此我暴露了NAT转出的IP也没什么大碍 引言 postgresql与mysql目前都是非常受人欢迎的两大数据库&#xff0c;其各有各的优势&#xff0c;初学者先使用简单一张图来说明两者区…

深入解析具名导入es6规范中的具名导入是在做解构吗

先说答案&#xff0c;不是 尽管es6的具名导入和语法非常相似 es6赋值解构 const obj {a: 1,f() {this.a}}const { a, f } objes6具名导入 //导出文件代码export let a 1export function f() {a}export default {a,f}//导入文件代码import { a, f } from ./tsVolution可以看出…