c++初阶------类和对象(下)

作者前言

🎂 ✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂
​🎂 作者介绍: 🎂🎂
🎂 🎉🎉🎉🎉🎉🎉🎉 🎂
🎂作者id:老秦包你会, 🎂
简单介绍:🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂
喜欢学习C语言、C++和python等编程语言,是一位爱分享的博主,有兴趣的小可爱可以来互讨 🎂🎂🎂🎂🎂🎂🎂🎂
🎂个人主页::小小页面🎂
🎂gitee页面:秦大大🎂
🎂🎂🎂🎂🎂🎂🎂🎂
🎂 一个爱分享的小博主 欢迎小可爱们前来借鉴🎂


类和对象

  • **作者前言**
  • 类的构造函数
    • 初始化列表
  • static成员
    • 静态成员
    • 静态成员函数
  • explicit关键字
    • 单参数的隐式类型转换
    • 多参数类型的隐式类型转换(c++11后支持)
  • 友元
    • 友元函数
    • 友元类
  • 内部类
  • 扩展
    • 拷贝小误区
    • 构造优化(编译器的优化)

类的构造函数

前面我们学习了类的构造函数的定义,如下:
在这里插入图片描述
这个就是我们之前写的构造函数的定义,叫做函数体内初始化,除了这样定义,还有另外一种定义叫初始化列表

初始化列表

使用这个主要是为了解决一些类型无法初始化

  1. 类中的引用无法初始化
    在这里插入图片描述
    可以看到使用函数体内初始化引用时是无法初始化引用变量的,因为在类中的成员是声明,在函数内才是定义(创建对象),const 也要在定义时初始化,为了解决引用和const在类的成员函数里面初始化不了,就有了初始化列表,
    初始化列表,初始化列表以冒号开头,后跟一系列以逗号分隔的初始化字段
		
		Date()
			//初始化列表
			:_a(d1._a)
			,_b(30)
		{
			//函数体内定义
			_year = d1._year;
			_month = (d1._month);
			_day = (d1._day);
		}

这里是一个类的默认构造函数,

  1. 假设初始化列表没有写内置类型的定义和函数体内定义也没有,内置类型就是随机值(编译器定义的)
  2. 如果类的成员有自定义类型,没有在初始化列表定义,自定义类型会自动调用它本身的默认构造函数。
    无参的构造函数全缺省的构造函数以及编译器自己生成的都称为默认构造函数
    (不用传参的构造函数)
namespace naco
{

	
	class D
	{
	public:
		//默认构造
		D(int a = 20)
		{
			_a = 20;
		}
	private:
		int _a;
	};

	class Date
	{
	public:
		Date(int year, int month, int day)
			//初始化列表
			:_a(year)
			, _b(30)
			,A(20)//不想调用自己默认值默认构造,就传值
		{
			//函数体内定义
			_year = year;
			_month = (month);
			_day = (day);
		}
		~Date()
		{
			cout << _year << "-" << _month << "-" << _day << endl;
		}



	private:
		//声明
		int _year;
		int _month;
		int _day;
		int& _a;
		const int _b;
		D A;
	};
}

我们还可以在声明的时候定义,这样就可以哪怕初始化列表不写,也不会报错

class Date
	{
	public:
		Date(int year, int month, int day)
			//初始化列表
			:_a(year)
			,A(20)
		{
			//函数体内定义
			_year = year;
			_month = (month);
			_day = (day);
		}
		~Date()
		{
			cout << _year << "-" << _month << "-" << _day << endl;
		}



	private:
		//声明
		int _year;
		int _month;
		int _day;
		int& _a;
		const int _b = 100;
		D A;//自定义类型
	};

所以可以总结一下:
初始化列表主要针对三类

  1. 引用
  2. const修饰的变量
  3. 没有默认构造函数的自定义类型成员,有默认构造的对象,哪怕没有定义也会调用自己的默认构造,或者是不使用默认值的自定义类型成员

建议:

  1. 构造函数由初始化列表和函数体构成,缺一不可,
  2. 每个成员只能再初始化列表出现一次,但是不会影响函数体内初始化,在函数体内还可以出现
  3. 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关建议类中声明次序和初始化顺序一样
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,然后再初始化_a1
,

static成员

静态成员

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数静态成员变量一定要在类外进行初始化,
例子:
写出一个类,计算出一个程序中的类对象有多少个

class A
{
public:
	A(int a = 20)
	{
		_a = a;
		++count;
	}
	A(const A& d1)
	{
		_a = d1._a;
		++d1.count;
	}
	~A()
	{
		--count;
	}

	void Print()
	{
		cout << count << endl;
	}

private:
	//shngm
	static int count;//属于全部对象共同使用的.不会每个对象都有专属的count,而是全部对象公用这个count
	int _a;

};
//静态成员定义
int A::count = 0;
int main()
{
	 
	A a(10);
	A b(30);
	a.Print();
	return 0;
}

静态成员函数

  1. main函数之前就初始化了.而不是创建对象后才初始化,
  2. 只是放到类中,属于类的私有成员,
  3. 静态成员是全局的,所有对象共用,
  4. 静态成员只能在类外面定义,不属于类外访问,不能走构造函数的路
    静态成员访问形式:
A aa;
A::count;
aa.count;
//这两种都可以访问,

可能有些小可爱觉得不太方便,就会使用一下匿名对象,这个匿名对象和C语言的匿名结构体是不一样的,匿名对象的生命周期只是在一行中

class A
{
public:
	A(int a = 20)
	{
		_a = a;
		++count;
	}
	A(const A& d1)
	{
		_a = d1._a;
		++d1.count;
	}
	~A()
	{
		--count;
	}

	void Print()
	{
		cout << A::count << endl;
	}

private:
	//shngm
	static int count;
	int _a;

};
//定义
int A::count = 0;
int main()
{
	A().Print();//A()是一个匿名对象,生命周期在这一行,出了这一行,这个匿名对象就会被析构
	return 0;
}

A()就是匿名对象,生命周期在定义的那一行中,

静态成员函数

特点:没有this指针
调用静态成员函数和调用静态成员的方法是一样的,

在这里插入图片描述
可以自定义类型::静态成员函数对象.静态成员函数调用

注意: 静态成员函数可以直接调用静态成员
作用

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

explicit关键字

单参数的隐式类型转换

class A
{
public:
	A(int a = 20)
		:_a(a)
	{}
	A(const A& d1)
	{
		_a = d1._a;
	}
	~A()
	{
		cout << _a << endl;
	}
private:
	int _a;
};
int main()
{
	A tes = 20;
	return 0;
}

上面代码涉及到了内置类型对象隐式转换成自定义类型对象
在这里插入图片描述
需要注意的是支持这个方式是要构造函数的参数只有一个int类型参数(this不包含在内),前面我们知道这个临时变量具有常性,需要用const修饰的变量来接收,
能隐式互相转的内置类型是整形(int)浮点数,这里两种对是类型相近的,表示数据的大小。

内置类型转自定义类型的话,前提是自定义类型的构造函数必须是单参数构造函数
还有就是全缺省构造函数。和只有一个参数没有默认值的半缺省构造函数,都可以隐式转化
简单的理解就是只能传一个参数的构造函数可以
在这里插入图片描述

多参数类型的隐式类型转换(c++11后支持)

上面是只能传一个参数的隐式转换,如果是多参数的话可以这样

class A
{
public:
	 A(int a , int b = 20, int c=30)
		:_a(a)
		,_b(b)
		,_c(c)
	{

	}
	A(const A& d1)
	{
		_a = d1._a;
		_b = d1._b;
		_c = d1._c;
	}
	~A()
	{
		cout << _a << endl;
	}
private:
	int _a;
	int _b;
	int _c;


};
int main()
{

	A tes = {30, 20 ,10};
	const A& test = {60, 50, 10};//引用的是A(60,50,10)的临时变量
	return 0;
}

这里是要在c++11后才支持的,多参数的类型转换,一样的道理,

为了防止这些转换,cpp就有了一个explicit关键字

在这里插入图片描述
使用这个关键字来修饰构造函数就会防止有隐式转换了

友元

友元分为:友元函数和友元类

友元函数

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

class A
{
public:
	 A(int a , int b = 20, int c=30)
		:_a(a)
		,_b(b)
		,_c(c)
	{

	}
	A(const A& d1)
	{
		_a = d1._a;
		_b = d1._b;
		_c = d1._c;
	}
	~A()
	{
		cout << _a << endl;
	}
	//友元函数(不是任何类的成员函数)
	friend std::ostream& operator<<(std::ostream& out, const A& d1);

private:
	int _a;
	int _b;
	int _c;
};
std::ostream& operator<<(std::ostream& out, const A& d1)
{
	out << d1._a << d1._b << d1._c;//访问了类的私有成员,没有this指针
	return out;
}

特征

  1. ​友元函数可访问类的私有和保护成员,但不是类的成员函数

  2. 友元函数不能用const修饰

  3. 友元函数可以在类定义的任何地方声明,不受类访问限定符限制

  4. 一个函数可以是多个类的友元函数

  5. 友元函数的调用与普通函数的调用原理相同

友元类

class A
{
	
public:
	friend class B;
	A(int a, int b = 20, int c = 30)
		:_a(a)
		, _b(b)
		, _c(c)
	{

	}
	A(const A& d1)
	{
		_a = d1._a;
		_b = d1._b;
		_c = d1._c;
	}
	~A()
	{
		cout << _a << endl;
	}

private:
	int _a;
	int _b;
	int _c;
};
class B
{
public:
	B(int a = 20, int b = 30, int c = 40, int Ba = 50, int Bb = 60, int Bc = 70)
		:t(a,b,c)
		,_Ba(Ba)
		,_Bb(Bb)
		,_Bc(Bc)

	{

	}
	void Print()
	{
		cout << t._a << " " << t._b << " " << t._c << endl;//直接访问t的私有成员
	}
	~B()
	{
		cout << "B析构了" << endl;
	}

private:
	int _Ba;
	int _Bb;
	int _Bc;
	A t;
};
int main()
{

	B te = 50;
	te.Print();

	return 0;
}

在这里插入图片描述
特征

  1. 友元关系是单向的,不具有交换性。(友元类可以访问普通类的私有成员或者成员函数,前提是普通类声明过这个友元类)
  2. 友元关系不能传递(C是B的友元类,B是A的友元类,但是C不是A的友元类)
  3. 友元关系不能继承

内部类

如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类
不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越
的访问权限。
注意:内部类就是外部类的友元类,参见友元类的定义,内部类可以通过外部类的对象参数来访
问外部类中的所有成员。但是外部类不是内部类的友元。
如果内部类被public,可以在类外面进行定义,需要使用 外部类名:: 内部类,否则的话只能在外部类内定义使用,

class A
{
public:
	A(int a, int b, int c)
		:bb(20)
	{
		_a = a;
		_b = b;
		_c = c;
	}
private:
	class B
	{
	public:
		B(int b)
		{
			_bb = b;
		}
		~B()
		{
			A aa(30,40,50);
			aa._a++;
			aa._b++;
			aa._c++;
			
		}
	private:
		int _bb;
	};

private:
	int _a;
	int _b;
	int _c;
	B bb;//内部类
};
int main()
{

	A aa(1,1,1);
	//A::B bb(1);//内部类被oublic可以使用

	return 0;
}

特性:

  1. 内部类可以定义在外部类的public、protected、private都是可以的。
  2. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。

扩展

拷贝小误区

class A
{
public:
	A(int a = 10)
	{
		_a = a;
	}
	A(const A& d)
	{
		_a = d._a;
	}
private:
	int _a;
};
int main()
{
	A a1;
	A a2 = a1;//拷贝
	A a3(20);
	a1 = a3;//赋值
	return 0;
}
  1. 一个存在的对象拷贝构造另一个要创建的对象,就是拷贝构造
  2. 两个存在的对象使用=就是赋值

构造优化(编译器的优化)

随着时代的变迁,编译器对于一些代码优化了很好,比如构造函数
同一个表达式中,连续的构造+构造/ 构造+拷贝构造/拷贝构造+拷贝构造合二为一

在这里插入图片描述
红框中的大概意思就是,用1构造一个临时对象,然后用这个临时对象拷贝构造a4,但是结果却是调用了构造函数,所以就会有一个结论:

构造 + 构造=>构造

拷贝构造+构造=>构造
在这里插入图片描述

拷贝构造 + 拷贝构造=>拷贝构造
在这里插入图片描述

不同的编译器优化成度不同,但是普遍有正常的优化,有一些编译器优化可能是多个表达式优化
比如VS2019:
在这里插入图片描述
Linux下的g++编译器
在这里插入图片描述
就可以看出差别,不同的编译器优化的程度会不同。

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

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

相关文章

河北政采网2024年的入驻要求?

河北政采网2024年的入驻要求主要包括以下几个方面&#xff1a; 经营范围与资质&#xff1a;申请者需具有合法经营的营业执照&#xff0c;可以是一般纳税人、小规模纳税人或个体工商户。同时&#xff0c;申请者需要具备自主电商平台&#xff0c;该平台应为面向社会消费的专业销…

Linux学习(3)——使用Linux命令行

1.Shell是什么&#xff1f; shell本质上是Linux的应用程序&#xff0c;是Linux和用户进行沟通的桥梁 用户可以通过控制台终端输入各种命令&#xff0c;命令会被shell解析&#xff0c;解析后就会调用命令所对应的应用程序&#xff0c;应用程序又会去调用各种API接口以使用Linux内…

锐捷 EWEB auth 远程命令执行漏洞复现

一、漏洞信息 漏洞名称:锐捷 EWEB auth 远程命令执行漏洞 漏洞类别:远程代码执行 风险等级:高危 二、漏洞描述 锐捷睿易是锐捷网络针对商业市场的子品牌。拥有易网络、交换机、路由器、无线、安全、云服务六大产品线,解决方案涵盖商贸零售、酒店、KTV、网吧、监控安防…

【嵌入式——QT】文件系统和文件读写

【嵌入式——QT】文件系统和文件读写 文本文件读写二进制文件读写文件目录操作QCoreApplicationQFileQFileInfoQDirQTemporaryDir和QTemporaryFileQFileSystemWatcher 图示代码示例 文本文件读写 QT提供了两种读写纯文本文件的基本方法&#xff0c;一种是用QFile类的IODevice读…

java SSM科研管理系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 java SSM科研管理系统是一套完善的web设计系统&#xff08;系统采用SSM框架进行设计开发&#xff0c;springspringMVCmybatis&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S…

VS Code搭建windows+远程Linux上Docker的开发环境

在本地windows桌面系统远程Linux上Docker搭建开发环境主要步骤如下&#xff1a; 一、安装vs code和插件 在windows系统上安装vs code&#xff0c;并安装好remote-ssh、dev-container插件&#xff0c;也可以直接安装Remote Development&#xff0c;他会默认把vs code远程的几种…

网络请求与数据解析

urllib是Python自带的标准库中用于网络请求的库 &#xff0c;无需安装&#xff0c;直接引用即可。通常用于爬虫开发、API&#xff08;应用程序编程接口&#xff09;数据获取和测试。 urllib库的几个模块&#xff1a; urllib.request :用于打开和读取URLurllib.error:包含提出…

大模型相关算法模型学习

对Transformer中Add&Norm层的理解-CSDN博客 GPT模型总结【模型结构及计算过程_详细说明】_gpt结构-CSDN博客 推荐30个以上比较好的中文nlp意图识别模型源码&#xff1f;-CSDN博客 Few-shot learning&#xff08;少样本学习&#xff09;入门 - 知乎 (zhihu.com) 零次学习…

程序人生 - 爬虫者,教育也!

作为一个站长&#xff0c;你是不是对爬虫不胜其烦&#xff1f;爬虫天天来爬&#xff0c;速度又快&#xff0c;频率又高&#xff0c;服务器的大量资源被白白浪费。 看这篇文章的你有福了&#xff0c;我们今天一起来报复一下爬虫&#xff0c;直接把爬虫的服务器给干死机。 本文有…

Linux常见指令总结

ls&#xff1a;显示当前目录下文件列表 常用的命令行参数&#xff1a; -l 显示更多的文件属性 -a 显示所有的文件/目录&#xff08;包括隐藏的&#xff09; -d 只显示目录 ps&#xff1a;参数可以叠加使用。 例如&#xff1a;ls -la 显示所有文件…

基于 Jenkins 搭建一套 CI/CD 系统

一、CI/CD环境介绍 本次要实现如下效果&#xff0c;开发人员完成功能开发并提交代码到gitlab仓库&#xff0c;jenkins自动完成拉取代码、编译构建、代码扫描&#xff08;sonarqube&#xff09;、打包&#xff0c;再自动化完成部署到Tomcat服务器提供访问。 环境准备三台Centos…

初窥机器学习

人工智能 近几年来&#xff0c;人工智能&#xff08;AI&#xff09;已成为家喻户晓的术语&#xff0c;我们在游戏、电影&#xff08;还记得J.A.R.V.I.S吗&#xff1f;&#xff09;和书籍中经常看到它的提及和描绘&#xff0c;但人工智能究竟是什么呢&#xff1f; 人工智能简单…

远程同声传译如何实现?哪里提供专业的远程同声传译?

远程同传声传译&#xff0c;即线上同传翻译&#xff0c;是指翻译员通过非现场的网络方式进行的同声传译(实时翻译)。远程同声传译的实现依赖于一系列先进的技术手段和高效的协作流程。这一服务模式的出现&#xff0c;不仅打破了传统同声传译的地域限制&#xff0c;还为全球范围…

2024上半年软考初级《程序员》报名考试全流程梳理

​2024年软考程序员考试报名时间节点&#xff1a; 报名时间&#xff1a;上半年3月18日到4月15日&#xff0c;下半年8月19日到9月15日&#xff08;各地区报名时间不同&#xff0c;具体日期见官方通告&#xff09; 准考证打印时间&#xff1a;上半年5月20日起&#xff0c;下半年…

HarmonyOS NEXT应用开发之使用AKI轻松实现跨语言调用

介绍 针对JS与C/C跨语言访问场景&#xff0c;NAPI使用比较繁琐。而AKI提供了极简语法糖使用方式&#xff0c;一行代码完成JS与C/C的无障碍跨语言互调&#xff0c;使用方便。本示例将介绍使用AKI编写C跨线程调用JS函数场景。通过调用C全局函数&#xff0c;创建子线程来调用JS函…

项目实战-tpshop商城项目

项目实战-tpshop商城项目 环境部署准备软件工具准备远程连接测试远程连接测试-查看虚拟机IP地址远程连接测试-检测本机与虚拟机是否连通远程连接测试-通过远程工具连接linux服务器 常见问题处理 环境部署项目技术架构介绍部署tpshop项目-tpshop验证数据库验证用户信息表熟悉商品…

【国产】API接口管理平台的产品设计与搭建讲解

【国产接口管理平台】PhalApi Pro (π框架专业版) PhalApi Pro (发音&#xff1a;π框架专业版)&#xff0c;是一款国产企业级API接口管理平台&#xff0c;可以零代码、快速搭建API接口开发平台、接口开放平台、接口管理平台。基于PhalApi开源接口开发框架&#xff0c;通过低代…

可视化表单流程编辑器为啥好用?

想要提升办公率、提高数据资源的利用率&#xff0c;可以采用可视化表单流程编辑器的优势特点&#xff0c;实现心中愿望。伴随着社会的进步和发展&#xff0c;提质增效的办公效果一直都是很多职场办公团队的发展需求&#xff0c;作为低代码技术平台服务商&#xff0c;流辰信息团…

MySQL8.0安装教程+使用Navicat远程连接

MySQL8.0安装教程使用Navicat远程连接 版本&#xff1a;MySQL8.0.28 环境&#xff1a;Windows11 1.MySQL下载 进入官网https://www.mysql.com/进行下载&#xff1a; 2.安装MySQL 下载好后&#xff0c;点击运行程序开始安装&#xff0c;安装步骤如下&#xff1a; 以下步骤验…

MSigDB数据库 | 富集分析需要的基因集该去哪里找?如何选择适合自己数据的基因集?

富集分析可以说是我们的老帮手了&#xff01;进行富集分析&#xff0c;就不能不提基因集&#xff0c;那基因集我们该去哪里找呢&#xff1f;我们又该如何选择适合自己数据的基因集呢&#xff1f;咱们今天就来浅浅唠一唠&#xff01; 最常见的操作就是去MSigDB数据库找现成的基因…