【C++初阶】类和对象(下)

news2024/12/23 18:14:37

一.再谈构造函数

构造函数其实分为:

   1.函数体赋值

   2.初始化列表

之前所讲到的构造函数其实都是函数体赋值,那么本篇文章将会具体讲述初始化列表。

初始化列表

语法

一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟
一个放在括号中的初始值或表达式。

class Date
{
public:
Date(int year, int month, int day)
  : _year(year)
  , _month(month)
  , _day(day)
  {}
private:
    int _year;
    int _month;
    int _day;
};

上述代码即是初始化列表。

必须用初始化列表初始化的变量

需要注意的是,有几种变量必须要用初始化列表初始化:

   1.const 变量

   2.引用变量

   3.自定义变量

接下来我们一个一看。

const 变量

可以看到在函数体中对 const 变量是不可以初始化的,所以必须要在初始化列表中初始化;

引用变量

 很明显,对于引用变量也不能在函数体中初始化;这里还要注意给引用传参时,也要传引用,否则会出现类似野引用的情况,这种情况很危险。

自定义变量

对于自自定义变量,会去调用它的默认构造函数,所以不显式初始化自定义变量也行,但如果该自定义变量没有默认构造函数的话,就必须要显式初始化(关于默认构造函数:构造函数和析构函数)

如上图所示,对于没有默认构造函数的自定义变量,因为未显示初始化,所以编译器报了错。 

初始化列表的一个坑

我们先来看一段代码:

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

上面这段代码会输出什么呢?

答案是:1   随机值

为什么?

这就不得不说到初始化列表的一个有点坑的地方了。

成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后
次序无关;

也就是说,上述代码的初始化列表中,先初始化的是 _a2 变量,而 _a2 变量是初始化成 _a1 变量的,但此时 _a1 变量还没有初始化,所以就出现了随机值。

所以呢,初始化列表时最好按照声明的顺序初始化

总结

1.初始化列表其实是成员变量定义的地方,不管有没有写都会走一遍,且也只会走一遍

  private  中的其实是成员变量的声明;

2.尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变        量,一定会先使用初始化列表初始化。

3.初始化列表并不能完全代替函数体赋值


二.explicit 关键字

内置类型与自定义类型的隐式类型转换

先看这样一段1代码

class A
{
public:
	A(int a=1)
		:_a(a)
	{}
private:
	int _a;
};

int main()
{
	A a1(1);
	A a2 = 2;  //这句代码有问题吗

	return 0;
}

我们发现了一个令人有点摸不着头脑的代码: A  a2=2 ;

这是什么?

其实这就是隐式类型转换

内置类型先转换成自定义类型,然后构造一个A的临时对象(临时对象具有常属性),临时对象再拷贝构造a2 ,最后再调用构造函数,但是现在的编译器一般都会对这一过程进行优化,它是直接构造

我们可以验证下:

 可以看到 vs2022 是进行了优化的,直接调用构造函数。

那么如果我们不想让这种隐式类型转换发生该怎么办呢?

 只需再函数前面加上 explicit 关键字即可解决explicit 

 可以看到在加上这个关键字后,编译器就报错了。


三.static 成员

静态成员变量

1.声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;

   注意:静态成员变量一定要在类外进行初始化,且不加 static 关键字

              类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问;

class A
{
public:
	A(int b=1)
		:_b(b)
	{}

private:
	static int _a;  //声明
	int _b;
};

int A::_a = 1;   //定义

静态成员函数

2.用static修饰的成员函数,称之为静态成员函数

   注意:静态成员函数没有this指针,所以不能访问类里面的成员,也不能调用非静态成员                  函数;

static 成员属于类,属于类的每个对象共享,存储在静态区

成员变量 -- 属于每个一个类对象,存储在对象里面

静态成员也是类的成员,受public、protected、private 访问限定符的限制。


四.友元

友元函数

友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明(友元函数并不受访问限定符限制),声明时需要加friend关键字。

例:重载运算符  <<

我们知道 cout<< 能自动识别内置类型,并打印;如果想要用这个打印自定义类型的话,就要重载一个,如果重载在类中的话,那么它就属于类的成员函数了,第一个形参就是 this指针,所以我们使用的时候只能这样写:对象 << cout,这样是不是很别扭,所以要想按照原来的写法,就不能把这个函数写在类的内部,只能写在外部,但我们有序要访问类里面的成员,这就在类内部声明友元函数了。

class Eve
{
	friend ostream& operator<<(ostream& out, Eve& e);   //友元函数声明
public:
	Eve(int a,int b)
		:_a(a)
		,_b(b)
	{}

private:
	int _a = 1;
	int _b = 2;
};

ostream& operator<<(ostream& out, Eve& e)
{
	out << e._a <<" "<<e._b << endl;

	return out;
}
int main()
{
	Eve e(1,2);

	cout << e;

	return 0;
}

总结

1.友元函数可访问类的私有和保护成员,但不是类的成员函数
2.友元函数不能用const修饰
3.友元函数可以在类定义的任何地方声明,不受类访问限定符限制
4.一个函数可以是多个类的友元函数;
5.友元函数的调用与普通函数的调用原理相同;

友元类

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。

1.友元关系是单向的,不具有交换性

   比如A类和B类,在A类中声明B类为其友元类,那么可以在A类中直接访问B类的私有成员     变量,但想在B类中访问A类中私有的成员变量则不行。


2.友元关系不能传递
3.如果C是B的友元, B是A的友元,则不能说明C时A的友元;
4.友元关系不能继承,在继承位置再给大家详细介绍。

 


五.内部类

概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类

内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限

所以计算一个有内部类的类的大小时,只需要计算外部类的大小。

注意:内部类天生是外部类的友元类

特性:
1. 内部类可以定义在外部类的public、protected、private都是可以的。
2. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。
3. sizeof(外部类)=外部类,和内部类没有任何关系

class A
{
private:
	static int _a;
	int _b;
	class B
	{
	private:
		int _c;
	};
};

int main()
{
	cout << sizeof(A) << endl;   //会是多少呢?

	return 0;
}

 上述代码的结果是什么呢?

答案:4

因为只需要计算外部类的大小,而静态成员变量是存储在静态区的,并不在类中,所以只需计算成员变量 _b 的大小,很明显是4。


六.匿名对象

class A
{
public:
    A(int a = 0)
      :_a(a)
    {
        cout << "A(int a)" << endl;
    }
    ~A()
    {
        cout << "~A()" << endl;
    }
private:
    int _a;
};
class Solution 
{
public:
    int Sum_Solution(int n) 
    {
        //...
        return n;
    }
};
int main()
{
    A aa1;
    // 不能这么定义对象,因为编译器无法识别下面是一个函数声明,还是对象定义
    //A aa1();
    // 但是我们可以这么定义匿名对象,匿名对象的特点不用取名字,
    // 但是他的生命周期只有这一行,我们可以看到下一行他就会自动调用析构函数
    A();
    A aa2(2);
    // 匿名对象在这样场景下就很好用
    Solution().Sum_Solution(10);
    return 0;
}

🐬🤖本篇文章到此就结束了, 若有错误或是建议的话,欢迎小伙伴们指出;🕊️👻

😄😆希望小伙伴们能支持支持博主啊,你们的支持对我很重要哦;🥰🤩

😍😁谢谢你的阅读。😸😼

 

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

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

相关文章

学成在线笔记+踩坑(11)——认证授权介绍、网关认证,SpringSecurity+JWT+OAuth2

导航&#xff1a; 【黑马Java笔记踩坑汇总】JavaSEJavaWebSSMSpringBoot瑞吉外卖SpringCloud黑马旅游谷粒商城学成在线牛客面试题_java黑马笔记 目录 1 【认证模块】需求分析 1.1 什么是认证授权 1.2 业务流程 1.2.1 统一认证 1.2.2 SSO单点登录 1.2.3 第三方认证 2 Spr…

java面试笔记-01-集合面试题-介绍

好了,各位同学。下面我们开始新的篇章。就是Java集合相关的面试题。相信啊,说到集合呢,你肯定是比较熟悉的。在我们之前的课程中或者是学习中,大家用过哪些集合比较多呢?List,还有Map对吧? 虽然呢,你使用起来很熟悉,但是在面试的时候,面试官呢,可不会问一些使用的问…

算法修炼之练气篇——练气三层

博主&#xff1a;命运之光 专栏&#xff1a;算法修炼之练气篇 &#x1f353;&#x1f353;十进制数转化为十进制以下任意进制&#xff08;常用记忆一下&#xff09; #include<stdio.h> int main() {//输入10 2意思就是输入十进制10转化为2进制是多少。//输出1010int num…

Learn RabbitMQ with SpringBoot

文章目录 What is RabbitMQ?RabbitMQ Core conceptRabbitMQ ArchitectureInstall and setup RabbitMQ using DockerExplore RabbitMQ using management UICreate and setup Springboot3 project in intellijSpringboot and RabbitMQ Basic MessageConnection between Springbo…

【C++ 入坑指南】(03)Hello World

大概每个程序猿的第一个程序都是 Hello World , 这是梦开始的地方。本文是C 入坑指南的第三篇&#xff0c;让我们从最经典的 Hello World 开始。 看代码 #include <iostream>using namespace std;int main() {cout << "Hello, world!" << endl;r…

Linkage Mapper 构建区域生态系统地图的指南

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 &#x1f31f;专栏地址: Linkage Mapper解密数字世界链接 文章目录 引言一、简介二、确定地图范围三、收集和整理空间数…

算法修炼之练气篇——练气一层

博主&#xff1a;命运之光 专栏&#xff1a;算法修炼之练气篇 题目1157: 亲和数 这道题很简单&#xff0c;我写的也很简单&#xff0c;看一眼就懂 题目描述 古希腊数学家毕达哥拉斯在自然数研究中发现&#xff0c;220的所有真约数(即不是自身的约数)之和为&#xff1a; 1245…

【MyBatis】 MyBatis 动态SQL使用及原理

文章目录 前言1. 动态SQL概述2. if标签3. choose、when和otherwise标签4. trim标签5. set标签和where标签6. foreach7. bind8. 动态SQL解析原理总结 前言 MyBatis 是一个优秀的持久层框架&#xff0c;它提供了丰富的 SQL 映射功能&#xff0c;可以让我们通过 XML 或注解方式来…

@SpringBootApplication深入剖析

如下图 SpringBootApplication是springboot项目启动类的注解&#xff0c;也是程序的入口,本文就是具体解析一下这个注解到底做了什么 一.SpringBootApplication的构成 1.这个注解是一个组合注解&#xff0c;他是有三个注解合成的&#xff0c;对应图中的123步&#xff0c;而这三…

新的勒索软件加密自身以逃避防病毒

一种名为 Cactus 的新型勒索软件一直在利用 VPN 设备中的漏洞对“大型商业实体”的网络进行初始访问。 Cactus 勒索软件行动至少从 3 月开始就一直活跃&#xff0c;并正在寻求受害者的大笔支出。 虽然新的威胁参与者采用了勒索软件攻击中常见的策略——文件加密和数据窃取——…

大数据Doris(十七):Random Distribution和复合分区使用场景

文章目录 Random Distribution和复合分区使用场景 一、Random Distribution 二、复合分区使用场景 Random Distribution和复合分区使用场景 一、Random Distribution 如果 OLAP 表没有更新类型的字段&#xff0c;将表的数据分桶模式设置为 RANDOM&#xff0c;则可以避免严…

架构设计之需求分析

大家好&#xff0c;我是易安。 设计架构的第一步是需求分析。那么&#xff0c;为什么要做需求分析&#xff1f;如何做好需求分析&#xff1f;今天我们一起聊一聊需求分析这件事儿 为什么要做需求分析 为何要做需求分析&#xff1f; 首先&#xff0c;当然是因为我们做软件本身就…

迭代器失效问题,以及解决方法。

迭代器的主要作用就是让算法能够不用关心底层数据结构&#xff0c;其底层实际就是一个指针&#xff0c;或者是对指针进行了封装&#xff0c;比如&#xff1a;vector的迭代器就是原生态指针T* 。因此迭代器失效&#xff0c;实际就是迭代器底层对应指针所指向的空间被销毁了&…

【小沐学Python】Python实现Web服务器(Flask+Vue+node.js,web单页增删改查)

文章目录 1、简介1.1 flask1.2 vue 2、开发2.1 新建flask项目2.2 安装flask库2.3 新建flask的主脚本2.4 新建Vue项目2.5 安装vue项目依赖项2.6 新增组件Ping.vue2.7 Ping.vue增加HTTP请求2.8 美化vue前端页面2.9 新增组件Books.vue2.10 flask增加路由Books2.11 Books.vue增加HT…

什么是ChatGPT?怎么用?

最近全网爆火的黑科技&#xff0c;叫做chatGPT。ChatGPT声称&#xff0c;它的AI对话模型能在大范围、细粒度问题上给出普遍准确的答案。简单地说&#xff0c;AI对话模型可以达到基本不犯错误的水平了。那么到底这个ChatGPT是什么&#xff1f;怎么用&#xff1f;本篇文章就来带大…

算法修炼之练气篇——练气二层

博主&#xff1a;命运之光 专栏&#xff1a;算法修炼之练气篇 题目 1084: 用筛法求之N内的素数 题目描述 用筛法求之N内的素数。 输入格式 N 输出格式 0&#xff5e;N的素数 样例输入 100 样例输出 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 …

学系统集成项目管理工程师(中项)系列21a_整体管理(上)

1. 含义 1.1. 包括为识别、定义、组合、统一和协调各项目管理过程组的各种过程和活动而开展的工作&#xff0c;是项目管理中一项综合性和全局性的管理工作 2. 项目经理是整合者 2.1. 【21上选33】 2.1.1. 【19上选37】 2.1.2. 【22上选33】 2.2. 通过与项目干系人主动、全…

shell脚本(磁盘空间、服务状态)

1、判断当前磁盘剩余空间是否有20G&#xff0c;如果小于20G&#xff0c;则将报警邮件发送给管理员&#xff0c;每天检查一次磁盘剩余空间。 第一步&#xff1a;创建脚本名为shell1.sh如下&#xff1a; vim shell1.sh 第二步&#xff1a;做计划在shell1文件中&#xff0c;命令…

Kyligence Zen 简直就是一站式指标平台的天花板

一、Kyligence Zen是什么&#xff1f; 1、Kyligence Zen是做啥的&#xff1f; Kyligence Zen是一款指标分析和管理的工具&#xff0c;是基于 Kyligence 核心 OLAP 能力打造&#xff0c;Kyligence Zen 提供集业务模型、指标管理、指标加工、数据服务于一体的一站式服务&#x…

孙溟㠭20余载春秋,4000多方印章,这双质朴的手有多么倔强的生命力

作品的背后往往折射出艺术家人生的广度和厚度。 先锋篆刻、书画艺术家孙溟㠭&#xff0c; 上世纪90年代开始接触篆刻&#xff0c; 至今&#xff0c;20载有余&#xff0c;积累了4000多方篆刻作品。 在他创作纪念吴品超院士的作品《药生尘》时&#xff0c; 我们拍到了艺术家…