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

news2024/12/26 20:47:01

作者前言

🎂 ✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂
​🎂 作者介绍: 🎂🎂
🎂 🎉🎉🎉🎉🎉🎉🎉 🎂
🎂作者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++编译器
在这里插入图片描述
就可以看出差别,不同的编译器优化的程度会不同。

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

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

相关文章

避抗指南:如何寻找OLED透明屏供应商

寻找OLED透明屏供应商&#xff0c;你可以按照以下步骤进行&#xff1a; 明确需求&#xff1a;首先&#xff0c;你需要明确自己的需求&#xff0c;包括所需OLED透明屏的尺寸、分辨率、亮度、色彩饱和度等具体参数&#xff0c;以及预算和采购量。这有助于你更精准地找到符合需求的…

Django入门 整体流程跑通

Django学习笔记 一、Django整体流程跑通 1.1安装 pip install django //安装 import django //在python环境中导入django django.get_version() //获取版本号&#xff0c;如果能获取到&#xff0c;说明安装成功Django目录结构 Python310-Scripts\django-admi…

滑动窗口的概念,糊涂窗口综合征,nagle算法

目录 1.流量控制 2.滑动窗口 3.思考问题 1.流量控制 一般来说,我们总是希望数据传输得更快一些,但如果发送方把数据发送得过快,接收方就可能来不及接收,这就会造成数据的丢失.所谓流量控制(flow control)就是发送方的发送速率不要太快,要让接收方来得及接收. 2.滑动窗口 T…

【VS Code插件开发】自定义指令实现 git 命令 (九)

&#x1f431; 个人主页&#xff1a;不叫猫先生&#xff0c;公众号&#xff1a;前端舵手 &#x1f64b;‍♂️ 作者简介&#xff1a;前端领域优质作者、阿里云专家博主&#xff0c;共同学习共同进步&#xff0c;一起加油呀&#xff01; ✨优质专栏&#xff1a;VS Code插件开发极…

WebServer -- 架构图 面试题(上)

目录 &#x1f382;前言 &#x1f33c;流程图 && 架构图 1&#xff09;什么是 WebServer 2&#xff09;服务器基本框架 3&#xff09;Reactor && Proactor 模式 4&#xff09;同步 I/O 模拟Proactor模式&#xff08;Linux&#xff09; 5&#xff09;主从…

小白刷题CTF show web方向

web01 右键查看源代码&#xff0c;再使用在线解密&#xff0c;就可以得出答案了 web02 sql注入 admin or 11 或者 1 or 11可以登录查询几个字段&#xff1a;1 or 11 order by 3 # 使用此语句&#xff0c;判断列数。 order by 3不会出错&#xff0c;但是order by 4就没有显示…

上传文件携带参数总是deubg不进去

const { data } await createVerificationMaterialApi({file: info.file,name: file,filename: info.file.name,data: { ids },})//这样传参数&#xff0c;网络里看发的请求会是如下样子&#xff0c;这样debug不到代码里正确方法 const { data } await createVerificationMat…

这下爽了,全是特殊版实用软件,功能强大还免费

闲话少说&#xff0c;直接上狠货。 1、我的ABC软件工具箱 简洁而不失强大&#xff0c;我的ABC软件工具箱是您批量处理办公任务的得力小助手。完全免费&#xff0c;界面清新无广告&#xff0c;让您轻松开启高效办公之旅。 面对日常办公中繁多的文件处理需求&#xff0c;如内容…

1.Datax数据同步之Windows下,mysql数据同步至另一个mysql数据库

目录 前言步骤操作大纲步骤明细其他问题 前言 Datax是什么&#xff1f; DataX 是阿里巴巴集团内被广泛使用的离线数据同步工具/平台&#xff0c;实现包括 MySQL、SQL Server、Oracle、PostgreSQL、HDFS、Hive、HBase、OTS、ODPS 等各种异构数据源之间高效的数据同步功能。准备…

IO学习--02

标准IO由ANSI C库说明&#xff0c;在很多系统都实现了标准IO库。标准IO库处理很多细节&#xff0c;如缓冲的分配、优化长度执行IO等&#xff0c;使得用户不需要考虑选择合适的长度。标准IO是在系统调用函数构建的&#xff0c;便于用户使用。 标准IO的所有操作都是围绕流&#x…

c语言经典测试题12

1.题1 float f[10]; // 假设这里有对f进行初始化的代码 for(int i 0; i < 10;) { if(f[i] 0) break; } 上述代码有那些缺陷&#xff08;&#xff09; A: for(int i 0; i < 10;)这一行写错了 B: f是float型数据直接做相等判断有风险 C: f[i]应该是f[i] D: 没有缺…

LLM PreTraining from scratch -- 大模型从头开始预训练指北

最近做了一些大模型训练相关的训练相关的技术储备,在内部平台上完成了多机多卡的llm 预训练的尝试,具体的过程大致如下: 数据准备: 大语言模型的训练依赖于与之匹配的语料数据,在开源社区有一群人在自发的整理高质量的语料数据,可以通过 以下的一些链接获取 liwu/MNBVC…

Java多线程——对象的原子更新

目录 引出对象原子更新AtomicReferenceAtomicLongFieldUpdaterABA问题 创建线程有几种方式&#xff1f;方式1&#xff1a;继承Thread创建线程方式2&#xff1a;通过Runnable方式3&#xff1a;通过Callable创建线程方式4&#xff1a;通过线程池概述ThreadPoolExecutor API代码实…

在VMvare中虚拟机安装centos7和初始设置

下载镜像 阿里云的镜像站&#xff1a;https://mirrors.aliyun.com/centos/7/isos/x86_64/ 创建虚拟机过程 虚拟机创建过程比较简单&#xff0c;以下在VMvare16中进行安装 点击左上角&#xff0c;文件-新建虚拟机&#xff1a; 选择典型 选择刚刚下载好的镜像 输入虚拟机…

#QT(本地音乐播放器)

1.IDE&#xff1a;QTCreator 2.实验&#xff1a;之前做的音乐播放器只做了一个界面&#xff0c;是因为跟的课程发现到后面需要付费&#xff0c;并且WINGW6.2.0运行QMediaPlayer时无法运行&#xff0c;会崩溃&#xff0c;现在退一步用WINGW5.12.2做一个本地音乐播放器 3.记录&am…

012集——显示高考天数倒计时——vba实现

以下代码实现高考倒计时&#xff1a; Sub 高考倒计时() 高考日期 CDate("06,07," & Year(Date)) If Date > 高考日期 Then高考日期 CDate("06-07-" & Year(Date) 1) End If 年月日 Year(Date) & "年" & Month(Date) &am…

鲜花销售小程序|基于微信小程序的鲜花销售系统设计与实现(源码+数据库+文档)

鲜花销售小程序目录 目录 基于微信小程序的鲜花销售系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1前台功能模块 2、后台功能模块 1、管理员功能模块 四、数据库设计 1、实体ER图 2、具体的表设计如下所示&#xff1a; 五、核心代码 六、论文参考 七、…

LabVIEW多表位数字温湿度计图像识别系统

LabVIEW多表位数字温湿度计图像识别系统 解决数字温湿度计校准过程中存在的大量需求和长时间校准问题&#xff0c;通过LabVIEW开发平台设计了一套适用于20多个表位的数字温度计图像识别系统。该系统能够通过图像采集、提取和处理&#xff0c;进行字符训练&#xff0c;从而实现…

LiveGBS流媒体平台GB/T28181功能-海康摄像头国标语音对讲大华摄像头国标语音对讲GB28181语音对讲需要的设备及服务准备

LiveGBS海康摄像头国标语音对讲大华摄像头国标语音对讲GB28181语音对讲需要的设备及服务准备 1、背景2、准备2.1、服务端必备条件&#xff08;注意&#xff09;2.2、准备语音对讲设备2.2.1、 大华摄像机2.2.1.1、 配置接入示例2.2.1.2、 配置音频通道编号 2.2.2、 海康摄像机2.…

现货黄金交易网上有用的交易技巧

在不同的现货黄金交易网上&#xff0c;经常有投资者分享交易技巧。由于在网上发文没什么限制&#xff0c;所以这些交易技巧都是泥沙俱下&#xff0c;质量良莠不齐。不过也有一些是有用的&#xff0c;下面我们就来介绍一下现货黄金交易网上那些有用的交易技巧。 培养防守意识。什…