从入门到精通C++之类和对象(续)

news/2024/5/17 8:18:35

目录

  • 初始化列表
  • 构造函数?拷贝构造?
  • 浅谈explicit关键字
    • 友元
  • 内部类
  • static成员
  • 总结

在这里插入图片描述

初始化列表

引入初始化列表:简化代码,提高效率

在编程中,初始化列表是一种用于在创建对象时初始化成员变量的快捷方式。通过初始化列表,可以在对象构造时直接为成员变量赋值,而无需在构造函数体内进行赋值操作。这不仅使代码更简洁清晰,还可以提高程序的执行效率。

在本文中,我们将深入探讨初始化列表的概念及其在不同编程语言中的应用。我们将介绍初始化列表的语法结构,并通过具体的示例代码演示如何在常见的编程语言中使用初始化列表。无论您是初学者还是有一定经验的开发者,本文都将为您带来有价值的信息。

初始化列表的格式

class AA
{
public:AA(int n):_a(n),_b(n){}
private:int _a;int _b;
};

d队列的初始化列表

	MyQueue(int n,int &rr):_pushst(n)//调用构造函数, _popst(n),_size(0){}

注意
1、对于上面的初始化列表,_pushst_popst是自定义类型,所以后面加个括号其实就是调用它的构造函数,我们可以这样理解

2、如果我们要初始化const修饰的变量时,只能在初始化列表中初始化,因为const修饰的变量具有常性,所以只能在初始化列表中初始化

3、当我们要初始化一个成员变量是引用时,也必须在初始化列表中初始化

注意:初始化列表是成员变量定义的地方,而类中的成员变量只是成员变量的声明

如果我们不写初始化列表会生成初始化列表吗?

答案是肯定的,我们可以在成员变量声明的时候给一些缺省参数,我们可以定义一个类,然后用调试器进行调试,在调试中我们可以发现,我们进入这个类的时候会直接跳到缺省参数的那几行,我们可以打开监视器进行观察,也可以看见,类中的成员就是用缺省值进行初始化的
在这里插入图片描述

构造函数?拷贝构造?

int main()
{AA a1(1);//构造函数AA a2 = a1;//拷贝构造AA a3 = 1;//?return 0;
}

第一个是构造函数第二个是拷贝构造,那第三个是什么呢?

第三个是隐式类型转换
在C语言中下面代码会生成一个临时变量

double b=3.3;
int a=b;

对于上面代码会生成一个临时变量,b先生成一个临时变量tmp,tmp是int类型,然后tmp再赋值给a

在这里插入图片描述
所以回归正传,刚刚我们用一个类等于一个数字,其实是一个隐式类型转换,本质是1先调用构造函数创建一个tmp的对象,然后再利用tmp再拷贝拷贝构造给a3

如果用AA&a3会报错,因为1具有常性,a3是tmp的引用a3可以修改,但是因为常性不能修改,所以会报错,这里就是权限的放大,所以我们可以在前面加一个const

	const AA& a3 = 1;

通过下面题目来引入一个初始化列表的规则

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();
}A. 输出1  1B.程序崩溃C.编译不通过D.输出1  随机值

对于上面这道题肯定不会选择A,因为往往这种题,都不可能这么直接,更不可能选择B,因为B是程序崩溃,往往程序崩溃只会出现在野指针和空指针中,只有从c和D中选,肯定可以排除C因为不可能编译错误。

从上面的题目中我们就可以得到一个规则,初始化列表的初始化顺序与初始化列表的顺序无关,只与声明时的顺序有关

上面我们讨论的是只有一个参数的时候的初始化,当有两个参数时我们应该如何传参呢

两个参数的参数列表的传参和数组类似

class AA
{
public:AA(int n = 1, int m = 2):_a(n), _b(n){}
private:int _a = 1;int _b = 0;
};
int main()
{AA a1(1);AA a2 = a1;const AA& a3 = 1;AA aa4 = { 1,2 };return 0;
}

当有两个参数的时候,就可以利用C99的语法进行初始化,其实等号也可以省略,最好把等号加上

浅谈explicit关键字

前面我们谈了隐式类型转换,如果我们不想进行隐式类型转换可以在函数前面加一个explicit关键字

智能指针是explicit关键字的使用场景

友元

友元函数就是全局函数,只不过是写在了类中,友元函数可以直接访问类中的私有成员变量,下面我们简单的写一个友元函数作为示范:
在声明中可以像下面这样声明:

	friend ostream& operator<<(ostream& out, const Date& d);friend istream& operator>>(istream& in, Date& d);

一般情况下,我们都会把友元函数的声明声明在类中的最前面,声明完了之后,友元函数在定义中还是像正常函数一样写,前面不用加friend

友元的特性

  1. 友元关系是单向的,不具有交换性。
    比如上述Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接
    访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。
  2. 友元关系不能传递
    如果C是B的友元, B是A的友元,则不能说明C时A的友元。
  3. 友元关系不能继承,在继承位置再给大家详细介绍。

出了友元函数还有友元类,在友元类中我们可以用另一个类中的私有成员变量

下面是友元类的声明

class Time
{friend class Date;   // 声明日期类为时间类的友元类,则在日期类中就直接访问Time类
中的私有成员变量
public:Time(int hour = 0, int minute = 0, int second = 0): _hour(hour), _minute(minute), _second(second){}private:int _hour;int _minute;int _second;
};
class Date
{
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}void SetTimeOfDate(int hour, int minute, int second){// 直接访问时间类私有的成员变量_t._hour = hour;_t._minute = minute;_t._second = second;}private:int _year;int _month;int _day;Time _t;
};

内部类

内部类就是、一个类中定义另一个类
内部类的特性:内部类是外部类的天生的友元类,内部类可以随意访问外部类的成员变量

注意:内部类也是一个单独的类,唯一的区别是受到了外部类域的限制,所以计算外部类的大小的时候,不需要加上内部类的大小,只需要算外部类的成员变量的大小即可

如果内部类定义在Public中则外面也可以访问,如果内部类定义在private中则只有类的内部才能访问

static成员

我们来计算一下下面的类的大小:

class BB
{
public:private:int _b1;static int _b1;
};

注意成员变量不存函数和静态变量,一个存放在代码区,一个存放在静态区,所以在计算类的大小的时候,我们也不计算static修饰的成员变量

在C语言中我们知道,static修饰的变量只初始化一次,且在定义的时候初始化,因为在类中的是声明所以我们不应该给成员变量缺省值,也不应该将static修饰的成员变量放在初始化列表中进行初始化

正确的初始化方法如下:

class BB
{
public:private:int _b1;static int _b1;
};
int BB::_b1 = 1;
int main()

特性

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

总结

通过本文的介绍,我们深入探讨了几个编程中的关键概念:友元、初始化列表、静态成员变量以及内部类。友元使得类之间的访问更加灵活,但也需要慎重使用以保持封装性;初始化列表能够简化对象的构造过程,提高代码效率;静态成员变量共享于类的所有对象,是实现全局数据共享和类特性存储的有效方式;内部类则可以在一个类的内部定义另一个类,便于组织和封装相关的功能。

深入理解这些概念对于成为一名优秀的程序员至关重要。熟练掌握它们不仅可以提高代码的质量和效率,还能够拓展我们的编程思维,使我们更加灵活地应对不同的问题和挑战。

在实际编程中,我们应该根据具体情况合理运用这些概念,从而编写出清晰、高效且易于维护的代码。希望本文能够为您在编程学习和实践中提供一些帮助和启发。让我们继续不断学习和探索,成为更加优秀的程序员!


http://www.mrgr.cn/p/48513003

相关文章

第十五届蓝桥杯大赛软件赛省赛 C/C++ 大学 B 组(基础题)

试题 C: 好数 时间限制 : 1.0s 内存限制: 256.0MB 本题总分&#xff1a;10 分 【问题描述】 一个整数如果按从低位到高位的顺序&#xff0c;奇数位&#xff08;个位、百位、万位 &#xff09;上 的数字是奇数&#xff0c;偶数位&#xff08;十位、千位、十万位 &…

NGINX Ingress Controller 设置未配置过的域名增加默认路由

背景 k8s 集群对应的公网 slb ip 经常被人绑定域名,监控侧经常会收集到 502 相关状态码的异常告警,着手处理这种bad case策略 1. 所有没有在ingress 配置过的域名要进行处理,即不是公司的、非法绑定到slb 上的域名要加上一条策略 2. NGINX Ingress Controller 设置未配置过…

基于达梦数据库开发-Java篇

文章目录 前言一、示例展示1.环境准备2.采用基础的jdbc调用3.采用扩展的mybatis调用 二、注意事项1.使用路径注解2.数据库对象的准确引用 三、可能异常1.无效的表或视图名2.无效的表或视图名3.网络通信异常 总结 前言 达梦提供了JDBC方式的驱动以便进行Java开发。默认情况下相…

web安全学习笔记(9)

记一下第十三课的内容。 准备工作&#xff1a;在根目录下创建template目录&#xff0c;将login.html放入其中&#xff0c;在该目录下新建一个reg.html。在根目录下创建一个function.php 一、函数声明与传参 PHP中的函数定义和其他语言基本上是相同的。我们编辑function.php …

基于RAM的几何变换——平移

基于RAM的几何变换——平移 一、平移的基本概念平移的概念很好理解,但是在具体操作中可能会涉及到两个问题:平移量有正数也有负数,涉及到Verilog语法中的有符号数处理 平移会导致部分像素超出我们的显示范围,对这部分的像素应当做丢弃处理二、MATLAB实现实现代码和实验结果…

IIC总线读取温度湿度传感器数据实验

iic.c #include "iic.h"extern void printf(const char* fmt, ...); /** 函数名 &#xff1a; delay_us* 函数功能&#xff1a;延时函数* 函数参数&#xff1a;无* 函数返回值&#xff1a;无* */ void delay_us(void) //微秒级延时 {unsigned int i 2000;while(i-…

C++ stl容器list的底层模拟实现

目录 前言&#xff1a; 1.创建节点 2.普通迭代器的封装 3.反向迭代器的封装 为什么要对正向迭代器进行封装&#xff1f; 4.const迭代器 5.构造函数 6.拷贝构造 7.赋值重载 8.insert 9.erase 10.析构 11.头插头删&#xff0c;尾插尾删 12.完整代码简单测试 总结&…

Day104:漏洞发现-漏扫项目篇武装BURP浏览器插件信息收集分析辅助遥遥领先

目录 插件类-武装BurpSuite-漏洞检测&分析辅助 1、如何加载插件&#xff1a; 2、漏洞检测类&#xff1a; Fiora TsojanScan RouteVulScan APIKit 3、分析辅助类&#xff1a; 插件类-武装谷歌浏览器-信息收集&情报辅助 HackBar Heimdallr Wappalyzer FindS…

学会解压

1,自我疗愈 压力日志拒绝精神内耗

JavaSE图书管理系统实战

代码仓库地址&#xff1a;Java图书管理系统 1.前言 该项目将JavaSE的封装继承多态三大特性&#xff0c;使用了大量面向对象的操作&#xff0c;有利于巩固理解 &#xff08;1&#xff09;实现效果 2.实现步骤 第一步先把框架搭建起来&#xff0c;即创建出人&#xff1a;管理员和…

Java 集合(ArrayList、LinkedList、HashMap、HashSet、LinkedHashMap、LinkedHashSet)【补充复习】

Java 集合&#xff08;ArrayList、LinkedList、HashMap、HashSet、LinkedHashMap、LinkedHashSet&#xff09;【补充复习】 Java 集合概述Collection 接口继承树Map 接口继承树 Collection 接口方法使用 iterator 接口遍历集合元素使用 forearch 遍历集合元素 List 接口List 实…

git 拉取或者推送代码报错问题解决

报错截图:当推送远程时,提示无法访问github地址 原因:在拉取或者是提交项目时,会发生git的http和https代理,我们电脑本地已经存在SSL协议的协议,可以取消http和https代理 在git中运行: git config --global --unset http.proxy git config --global --unset https.proxy…

【VUE】使用Vue和CSS动画创建滚动列表

使用Vue和CSS动画创建滚动列表 在这篇文章中&#xff0c;我们将探讨如何使用Vue.js和CSS动画创建一个动态且视觉上吸引人的滚动列表。这个列表将自动滚动显示项目&#xff0c;类似于轮播图的方式&#xff0c;非常适合用于仪表盘、排行榜或任何需要在有限空间内展示项目列表的应…

【MYSQL锁】透彻地理解MYSQL锁

&#x1f525;作者主页&#xff1a;小林同学的学习笔录 &#x1f525;mysql专栏&#xff1a;小林同学的专栏 目录 1.锁 1.1 概述 1.2 全局锁 1.2.1 语法 1.2.1.1 加全局锁 1.2.1.2 数据备份 1.2.1.3 释放锁 1.2.1.4 特点 1.2.1.5 演示 1.3 表级锁 1.3.1 介绍 …

paddleocr图片文本识别

1. paddleocr  PaddleOCR 是一个基于 PaddlePaddle 深度学习框架的开源 OCR(Optical Character Recognition,光学字符识别)工具。它提供了一系列的预训练模型和工具,可以用于文本检测、文本识别和文本方向检测等任务。 提供了易于使用的 Python API,可以轻松地在你的项目…

Docker入门实战教程

文章目录 Docker引擎的安装Docker比vm虚拟机快 Docker常用命令帮助启动类命令镜像命令docker imagesdocker searchdocker pulldocker system dfdocker rmi 容器命令redis前台交互式启动redis后台守护式启动Nginx容器运行ubuntu交互式运行tomcat交互式运行对外暴露访问端口 Dock…

HarmonyOS NEXT应用开发之图片缩放效果实现

介绍 图片预览在应用开发中是一种常见场景,在诸如QQ、微信、微博等应用中均被广泛使用。本模块基于Image组件实现了简单的图片预览功能。 使用说明:双指捏合缩放图片大小 双击图片进行图片的大小切换 图片在放大模式下,滑动图片查看图片的对应位置效果图预览实现思路image组…

【python之DRF学习】三大方法之认证

title: 【python之DRF学习】三大方法之认证 date: 2024-04-17 21:00:56 星期三 updated: 2024-04-17 21:01:00 星期三 description: cover: 内置三大方法: drf之APIView内部的必须会经过的三大认证/方法: 认证、权限、频率一、认证组件 1、简介 登录认证的限制​ 认证组件…

软考——程序设计语言

1.低级语言和高级语言 计算机硬件只能识别由0、1组成的机器指令序列&#xff0c;即机器指令程序&#xff0c;因此机器指令是最基本的计算机语言。由于机器指令是特定的计算机系统所固有的、面向机器的语言&#xff0c;所以用机器语言进行程序设计时效率很低&#xff0c;程序的…

死锁

多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能运行,而导致俩个或者多个线程都在等待对方释放资源。 package syn;public class DeadLock {public static void main(String[] args) {Makeup s1 = new Makeup(0,"小明");Makeup s2 = new Makeup(…