【C++第四课-类和对象下】初始化列表、静态成员函数、静态成员变量、explicit关键字(隐式类型转换)、友元函数、友元类、内部类、编译器的常见优化

目录

  • 再谈构造函数
    • 初始化列表
    • 初始化列表解决的问题:
    • 静态成员函数、成员变量
    • explicit关键字
  • 友元
    • 友元函数
    • 友元类
  • 内部类
  • 编译器的常见优化(了解)
    • 优化1

再谈构造函数

初始化列表

有一些成员变量是无法在函数体内初始化的,eg:引用、const、自定义类型没有默认构造

Date(int year = 1, int month = 1, int day = 1)
{
	//函数体内初始化
	_year = year;
	_month = month;
	_day = day;
}

Date(int year = 1, int month = 1, int day = 1)
		:_year(year)
		,_month(month)
		,_day(day)
	{
		//初始化列表初始化
	}

成员变量实在类里面声明的
如下图所示,因此对于引用、const只允许在定义的时候初始化,所以必须在初始化列表这定义
在这里插入图片描述

Date(int year = 1, int month = 1, int day = 1)
		:_ref(year)
		,_n(1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

对于上述代码
剩余的3个成员没有在初始化列表显示写出来定义
但是他也会定义,只是内置类型默认给的随机值
如果是自定义类型成员会去调用它的默认构造函数(如果没有默认构造函数就是编译不通过)

此时A这个类有默认构造函数(即不需要参数的构造函数),那么对于_aa不需要显示的写定义,他就会自动去调用它的默认构造函数

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

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
		:_ref(year)
		,_n(1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
	int& _ref;
	const int _n;
	A _aa;

};

此时A这个类没有默认构造函数,对于_aa来说就必须在初始化显示的定义了

class A
{
public:
	A(int a)
	{
		_a = a;
		cout<<"A(int a)";
	}
private:
	int _a;
};

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
		:_ref(year)
		,_n(1)
		,_aa(1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
	int& _ref;
	const int _n;
	A _aa;
};

在这里插入图片描述
对于下面中 int _year = 1;给的是缺省值,这样即使没有显示的在初始化列表中定义,_year也不会被初始化成随机值,而是初始化成1

private:
	int _year = 1;
	int _month;
	int _day;
	int& _ref;
	const int _n;
	A _aa;

初始化列表解决的问题:

1、必须在定义的地方显示初始化,引用、const、没有默认构造的自定义成员
2、有些自定义成员想要显示初始化,自己控制
尽量使用初始化列表初始化
构造函数能不能只要初始化列表,不要函数体初始化
不能,因为有些初始化或者检查的工作,初始化列表不能完全搞定

例题

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

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

静态成员函数、成员变量

静态成员函数指定类域就行
静态成员函数不能访问非静态的成员变量或函数,因为没有this
问题:计算到底创建了多少个A类的对象
对于上述问题我们可以在该类里面创建一个静态成员变量,在每次的构造函数或拷贝构造的时候++

class A
{
public:
	A(int a)
		:_a(a)
	{
		count++;
	}
	A(const A& y)
	{
		_a = y._a;
		count++;
	}
private:
	int _a;
	static int count;
};

int A::count = 0;

注意:
静态成员变量在类里面声明,在类外面定义
不能在类声明的时候给缺省值,因为塔不走初始化列表,缺失值是给初始化列表的
它不属于任何一个类的对象,它是属于整个类的
在这里插入图片描述

但是count是私有的在类外面无法访问
方法一:将count设置成公有

在这里插入图片描述
方法二:写一个get函数
这样的缺点就是,非静态的成员函数必须用对象调用
解决上述问题的方法:(1)建一个对象或者匿名对象(2)将Get函数写成静态成员函数

在这里插入图片描述
(1)匿名对象
匿名对象的作用域只有一行
在这里插入图片描述

(2)静态成员函数
因为静态成员函数没有this指针,所以可以不用创建对象,直接指定类域就行
在这里插入图片描述
对于静态成员变量,在算类对象的大小时是不算的,这个类创建的对象大小是4字节

explicit关键字

整型和指针不能隐式转,只能强制转
在这里插入图片描述
在这里插入图片描述

对于自定义类型,若该类是单参数的构造函数,或者多参数的构造函数(也可以,用半缺省只用一个参数初始化),或者是全缺省参数,或者需要多参构造函数
(1)int/double单参数的构造函数

class A
{
public:
	A(int a = 0)
		:_a(a)
	{}
	A(const A& y)
	{
		_a = y._a;
	}
private:
	int _a;
};
	
int main()
{
	A aa = 3;
	A bb = 3.1;
	//逗号表达式是具有返回值,返回值是最后一个数字
	A cc = (2024, 3, 29); //等价于 A cc = 3;
	return 0;
}

(2)用半缺省只用一个参数初始化

class A
{
public:
	A(int a, int b = 1,int c = 1)
		:_b(b)
		,_c(c)
	{}
	A(const A& y)
	{
		_a = y._a;
	}
private:
	int _a;
	int _b;
	int _c;
};
	
int main()
{
	A aa = 3;
	A bb = 3.1;

	return 0;
}

(3)全缺省参数的构造函数

class A
{
public:
	A(int a = 1, int b = 1,int c = 1)
		:_a(a)
		,_b(b)
		,_c(c)
	{}
	A(const A& y)
	{
		_a = y._a;
	}
private:
	int _a;
	int _b;
	int _c;
};
	
int main()
{
	A aa = 3;
	A bb = 3.1;

	return 0;
}

(4)需要多参构造函数

class A
{
public:
	A(int a, int b,int c)
		:_a(a)
		,_b(b)
		,_c(c)
	{}
	A(const A& y)
	{
		_a = y._a;
	}
private:
	int _a;
	int _b;
	int _c;
};
	
int main()
{
	A aa = {2024, 3, 29};

	return 0;
}

不想让自定义类型和内置类型的隐式类型的转换,构造函数+explicit(但强转可以)

在这里插入图片描述
强转
在这里插入图片描述

隐式类型转换可以用于list模板的创建

#include<vector>
#include<list>
#include<iostream>
using namespace std;

class A
{
public:
	A(int a)
		:_a(a)
	{}
	A(const A& y)
	{
		_a = y._a;
	}
private:
	int _a;
	int _b;
	int _c;
};
	
int main()
{
	//A aa = {2024, 3, 29};
	list<A> lt;
	A aa(1);
	lt.push_back(aa);

	lt.push_back(A(2));

	lt.push_back(3);
	return 0;
}

友元

在类外面突破封装,去访问私有保护的一种方式

友元函数

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

友元类

友元类的定义
friend + 类的声明
我想访问你,把我定义成你的友元
友元是单向关系

class A
{
public:
	friend class B;
private:
	int _a;
	
};
class B
{
private:
	int _b;
};

内部类

class A
{
private:
	int _a;
public:
	class B 
	{
	private:
		int _b;
	};
};

如果一个类定义在另一个类的内部,这个内部类就叫做内部类
内部类就是外部类的友元类
A和B的关系:B就是一个普通类,只是受A的类域和访问限定符限制,跟静态很像
B是A的友元,B能访问A 的成员,A不能访问B的成员
A的大小不算内部类
在这里插入图片描述
因为B在A 里面是public,所以在外面是可以访问的,但如果B在A的里面是private,那么B这个类只能在A 类里面去访问,外面的不能访问

A::B bb;

在这里插入图片描述

编译器的常见优化(了解)

不同编译器可能会不同

优化1

A aa1 = 1;

1、先用1构造一个临时对象
2、再用临时对象拷贝构造aa1
但实际上只用了一次构造函数
同一表达式中,连续的构造+构造/构造+拷贝构造/拷贝构造+拷贝构造会二合一

构造+构造- >构造
构造+拷贝构造 -> 构造
拷贝构造+拷贝构造 -> 拷贝构造

class A
{
public:
	A(int a)
		:_a(a)
	{
		cout << "A(int a)" << endl;
	}
	A(const A& i)
	{
		_a = i._a;
		cout << "A(const A& i)" << endl;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
private:
	int _a;
};

int main()
{
	A aa = 1;
	return 0;
}

在这里插入图片描述
下面这种情况就没有合二为一,因为不在同一表达式,编译器不敢
在这里插入图片描述
在同一表达式,编译器就会优化
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于javaweb+springboot开发的城市地名地址信息管理系统设计和实现

基于javaweb(springboot)城市地名地址信息管理系统设计和实现 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留言…

CPE-CLIP

input embeddings follow the form [ g 1 , g 2 , . . . , g L g_1,g_2,...,g_L g1​,g2​,...,gL​,w] 辅助信息 作者未提供代码

el-select下拉框无法显示 elementplus踩坑日常

在使用el-select的时候参考了官方文档&#xff0c;但下拉框无法显示 解决办法1&#xff1a;检查是否没有按需引入eloption只引入了elselect 解决办法2&#xff1a;在el-select里面加入:popper-append-to-body"false" <el-select:popper-append-to-body"fa…

基于亚马逊云EC2+Docker搭建nextcloud私有化云盘

亚马逊EC2云服务器&#xff08;Elastic Compute Cloud&#xff09;是亚马逊AWS&#xff08;Amazon Web Services&#xff09;提供的一种云计算服务。EC2代表弹性计算云&#xff0c;它允许用户租用虚拟计算资源&#xff0c;包括CPU、内存、存储和网络带宽&#xff0c;以满足计算…

Intellij IDEA 中 git 操作的快捷键

1.添加新建的文件 即add 操作 shift alt a 2.提交操作 即 commit操作 ctrl k 在窗口中可以用feature来声明此次更新的内容 3.提交操作 即push操作 ctrl shift k 4.拉去远程分支操作 即pull操作 ctrl t

C语言 --- 指针(5)

目录 一.sizeof和strlen对比 1.sizeof 2.strlen 3.strlen 和sizeof的对比 二.数组和指针笔试题目详解 回顾&#xff1a;数组名的理解 1.一维数组 2.字符数组 代码1&#xff1a; 代码2&#xff1a; 代码3&#xff1a; 代码4&#xff1a; 代码5&#xff1a; 代码6&am…

进程伪装详解

前言 当我们获取到一台主机的权限过后&#xff0c;拿到了自己想要搜集的信息&#xff0c;这时候我们就会留一个后门进行权限维持&#xff0c;权限维持的学问其实很深&#xff0c;今天就主要介绍其中一种比较简单的权限维持的方法 -- 进程伪装。 我们知道在windows里面有很多系…

Jetpack Navigation

1.Navigation的诞生与优势 这个留到Compose去学

探索机器学习的无限可能性:从初学者到专家的旅程

探索机器学习的无限可能性&#xff1a;从初学者到专家的旅程 在当今数字时代&#xff0c;机器学习无疑是最引人注目的技术之一。它已经深入到我们生活的方方面面&#xff0c;从个性化推荐到自动驾驶汽车&#xff0c;再到医疗诊断和金融预测。但是&#xff0c;即使我们已经见证…

时间复杂度之大O表示法

一、概念 O表示法&#xff1a; 设T( n)和 g( n)是正整数集到正实数集上的函数。 称T( n) O( g( n)) &#xff0c;当且仅当存在一个正常数 C 和 n0&#xff0c;使得对任意 的 n ≥ n0&#xff0c;有T( n) ≤ C g( n)。 其中&#xff1a;n 是算法输入的规模&#xff0c;如数组的…

【ghost】制作一个DOS启动盘用于备份/恢复系统

常用的DOS启动盘制作工具有USBoot、Ghost及FlashBoot等&#xff0c;本次DOS启动盘使用Ghost工具制作。 制作前准备 装有win10(或win7)系统的PC机&#xff0c;1台&#xff1b;U盘&#xff0c;1个&#xff1b;&#xff08;建议用户选择兼容性较高的金士顿U盘&#xff1b;此次演…

JAVA实战开源项目:快递管理系统(Vue+SpringBoot)

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容2.1 数据中心模块2.2 快递类型模块2.3 快递区域模块2.4 快递货架模块2.5 快递档案模块 三、界面展示3.1 登录注册3.2 快递类型3.3 快递区域3.4 快递货架3.5 快递档案3.6 系统基础模块 四、免责说明 一、摘要 1.1 项目介绍 …

Linux系统架构----LNMP平台部署中部署wordpress

Linux系统架构----LNMP平台部署中部署wordpress 一、LNMP的概述 LNMP为Linux平台&#xff0c;Nginx web服务软件&#xff0c;mysql数据库软件&#xff0c;PHP编辑语言LNMP系统架构相对于LAMP的优点是LNMP比较节省内存&#xff0c;主要支持静态请求&#xff0c;但在访问量大的…

力扣坑题:加一

注意数组扩容方法 /*** Note: The returned array must be malloced, assume caller calls free().*/ int* plusOne(int* digits, int digitsSize, int* returnSize) {int indexdigitsSize-1,pos1;while(index>0){digits[index]1;if(digits[index]10){digits[index]0;index-…

Django环境下使用Ajax

Django环境下使用Ajax 目录 Django环境下使用Ajax介绍前情提要示例JS实现Ajax实现 传递JSON格式数据传递文件数据Django自带的序列化组件基于jsonresponse序列化数据基于Django自带的serializers 介绍 AJAX 的主要目标是在不刷新整个页面的情况下&#xff0c;通过后台与服务器…

ROS2参数服务的实现

文章目录 1.参数服务的概念及应用场景1.1 概念1.2 应用场景 2.准备工作3.参数服务的实现3.1 参数数据类型的使用3.2 服务端的实现3.3 客户端的实现3.4 编译及运行 1.参数服务的概念及应用场景 1.1 概念 参数服务是以共享的方式实现不同节点之间数据交互的一种通信模式。保存参…

微信小程序-入门

一.通过 Npm方式下载构建 1.下载和安装Npm&#xff1a;Npm https://docs.npmjs.com/downloading-and-installing-node-js-and-npm 或者 https://nodejs.org/en/download/ 未安装npm 提示 以下以安装node安装包为例 按任意键继续 安装完成后 2. 下载和安装小程序开…

每日学习笔记:C++ STL 的Vector

Vector定义 Vector的大小与容量 Vector的函数 操作注意事项 Vector当作C数组 vector<bool>

Sora盈利新路径:基于技术创新与跨界融合

在数字化时代&#xff0c;技术的飞速进步为企业带来了前所未有的盈利机会。Sora作为一款前沿的AI视频生成工具&#xff0c;其盈利新路径可以基于技术创新与跨界融合两个核心策略来探索。 一、技术创新&#xff1a;持续引领行业前沿 Sora学习资料&#xff1a;使用方式完整文档…