C++入门:类和对象(后)

news2024/11/23 12:56:52

目录

前言:

一:static成员

(1)概念

(2)特性

(3)例子

二:explicit关键字 

三:内部类

(1)概念

(2)特性

(3)实例

四:匿名对象

(1)概念

(2)特性

(3)实例

五:拷贝对象时的一些编译器优化

(1)引入

(2)更多例子

代码:


前言:

C++专栏内容连贯,没展开讲的重要内容都在专栏往期。

为方便语法学习,直接展开std命名空间。

个人主页链接:派小星233的博客_CSDN博客-初阶数据结构,C语言,C++初阶领域博主 


一:static成员

(1)概念

  • 声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量,静态成员变量一定要在类外进行初始化
  • 用static修饰的成员函数,称之为静态成员函数。

(2)特性

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

(3)例子

问题:实现一个类,计算程序中创建出了多少个类对象。 

代码:

class A
{
public:
	A() //构造
	{ 
		++_scount; 
	}
	A(const A & t) //拷贝 
	{ 
		++_scount; 
	}
	static int GetACount() 
	{ 
		return _scount; 
	}
private:
	//声明这个静态变量是属于这个类的,没有定义
	static int _scount;
};

//定义并加域限定符(域限定也是符号表规则之一,不加的话类中的_scout只有声明)
int A::_scount = 0;

int main()
{
	cout << A::GetACount() << endl;
	A a1, a2;
	A a3(a1);
	//构造了三次,属于类A的静态变量加了3
	cout << A::GetACount() << endl;
	return 0;
}


二:explicit关键字 

我们看下面这段代码:
class A
{
public:
	A(int a = 0,int b = 0)
		:_a(a)
		,_b(b)
	{}
private:
	int _a;
	int _b;
};

int main()
{
	A a1 = 50;
	return 0;
}

上面的代码和结果说明了这样一个现象:

构造函数不仅可以构造与初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值的构造函数,还具有类型转换的作用

构造函数的隐式转换有的时候很灵活,有的时候却会导致代码的可读性下降,explicit关键字的作用就是修饰构造函数,禁止类型转换

代码:

//这段代码编译不通过
class Date
{
public:
	// 1. 单参构造函数,没有使用explicit修饰,具有类型转换作用
	// explicit修饰构造函数,禁止类型转换---explicit去掉之后,代码可以通过编译
	explicit Date(int year)
		:_year(year)
	{}
	/*
	// 2. 虽然有多个参数,但是创建对象时后两个参数可以不传递,没有使用explicit修饰,具
   有类型转换作用
	// explicit修饰构造函数,禁止类型转换
	explicit Date(int year, int month = 1, int day = 1)
	: _year(year)
	, _month(month)
	, _day(day)
	{}
	*/
	Date& operator=(const Date& d)
	{
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}
private:
	int _year;
	int _month;
	int _day;
};
void Test()
{
	Date d1(2022);
	// 用一个整形变量给日期类型对象赋值
	//构造函数没用explicit修饰时实际编译器背后会用2023构造一个无名对象,最后用无名对象给d1对象进行赋值
	d1 = 2023;
	// 将1屏蔽掉,2放开时则编译失败,因为explicit修饰构造函数,禁止了单参构造函数类型转换的作用
}

 

 


三:内部类

(1)概念

如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类,
它不属于外部类
内部类就是外部类的友元类,内部类可以访问外部类中的所有成员。但是外部类不是内部类的友元,不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。

(C++内部类并不常用)

(2)特性

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

(3)实例

代码:
class A
{
private:
	static int k;
	int _a = 0;
public:
	class B // B天生就是A的友元
	{
	public:
		void foo(const A& a)
		{
			//B类是A类友元,可以访问A
			cout << k << endl;
			cout << a._a << endl;
		}
	};
};

int A::k = 1;

int main()
{
	//虽然说类A对类B并没有访问权限,但是类B的定义是在A的域里面的
	//定义类B实例化对象时需要加上域限定符
	A::B b;
	A a1;
	b.foo(a1);

	return 0;
}

四:匿名对象

(1)概念

匿名对象指的是没有被赋予任何名称的对象,它们通常是在方法调用时临时创建的,并且只能被引用一次。虽然匿名对象没有名称,但它们仍然是一个完整的对象,具有对象的所有属性和方法。需要注意的是,由于没有名称,当使用匿名对象时无法再进行其他操作或访问该对象。

(2)特性

  1. 匿名对象没有名字,在定义对象时,不需要为其分配变量名,可以直接使用,且使用完毕后不需要释放内存,系统会自动回收。

  2. 匿名对象一般用于临时的对象操作,可以在一些函数中直接使用,无需定义变量。

  3. 匿名对象一般不能用于多次操作。如果需要多次操作一个对象,应当定义具名对象,否则代码会难以维护。

  4. 在定义匿名对象时,无法传递对象参数执行对象的构造函数

  5. 匿名对象的生命周期只有一条语句

(3)实例

代码:

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) 
	{
		//这里可以实现一系列计算,比方求n的阶乘
		//…………
		return n;
	}
};

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

五:拷贝对象时的一些编译器优化

(1)引入

注意:这部分的优化取决于编译器,大部分的编译器是存在优化的。

 但对象复杂的类对象,一个对象往往很大,这个时候拷贝的代价十分大,编译器会在保证安全的情况下进行优化。比如:使用去A函数构造一个对象,然后传值返回main函数去拷贝构造一个新对象。在未优化的情况下,你先拷贝了一份存储在预留的部分,然后在回收空间前又拷贝预留的一份到main函数栈帧中;这个行为在编译器看来是可以优化的,于是编译器直接拷贝了一份到main函数栈帧中,省去了在预留空间中的一次拷贝。(其他的连续拷贝也类似)

(2)更多例子

代码:

class A
{
public:
	A(int a = 0)
		:_a(a)
	{
		cout << "A(int a)" << endl;
	}
	A(const A& aa)
		:_a(aa._a)
	{
		cout << "A(const A& aa)" << endl;
	}
	A& operator=(const A& aa)
	{
		cout << "A& operator=(const A& aa)" << endl;
		if (this != &aa)
		{
			_a = aa._a;
		}
		return *this;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
private:
	int _a;
};

void f1(A aa)
{}
A f2()
{
	A aa;
	return aa;
}
int main()
{
	// 传值传参
	A aa1;
	f1(aa1);
	cout << endl;

	// 传值返回
	f2();
	cout << endl;

	// 隐式类型,连续构造+拷贝构造->优化为直接构造
	f1(1);

	// 一个表达式中,连续构造+拷贝构造->优化为一个构造
	f1(A(2));
	cout << endl;

	// 一个表达式中,连续拷贝构造+拷贝构造->优化一个拷贝构造
	A aa2 = f2();
	cout << endl;

	// 一个表达式中,连续拷贝构造+赋值重载->无法优化
	aa1 = f2();
	cout << endl;
	return 0;
}

 

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

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

相关文章

Spring整合MyBatis底层原理

Spring整合MyBatis底层原理 项目结构图 项目代码 build.gradle需要进入的依赖 // testImplementation(platform("org.junit:junit-bom:5.9.1")) // testImplementation("org.junit.jupiter:junit-jupiter")implementation("org.aspectj:aspect…

电池SOC和动力电池OCV功率联合估计研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

爱心方程(理科生的浪漫?)

目录 前言 C/C 源代码 扩展 Java Python HTML 前言 这个在大一的时候就想找了&#xff0c;然后后面是找到了一个&#xff0c;但是忘记出处了。我决定把可以找到的所有爱心给整理一下&#xff0c;为了实现“理科生的浪漫”&#xff01;&#xff01;&#xff01; C/C 首先…

你认为年轻人存款难吗?难啊难,难如上青天!!!

近日&#xff0c;有调查称“大概五分之一的年轻人存款在一万元以内。10万元存款是一个“坎”&#xff0c;存款超过10万就会超过53.7%的人。”“年轻人”“存款”两个词碰撞在一起&#xff0c;引来了广泛的关注和讨论。你认为年轻人存款难吗&#xff1f;可以从以下几个角度发表你…

Linux Nacos 设置systemctl service 并添加为开机启动

为方便在启动服务器时&#xff0c;不需要一个一个手动启动服务&#xff0c;需要把nacos设置为开机启动。方法如下&#xff1a; 在/usr/lib/systemd/system 目录下面添加nacos.service脚本&#xff1a; # 下面这一行必须有&#xff0c;不然会报错 #vim /usr/lib/systemd/system…

libevent(3)IO模型基础知识

一、用户态和内核态 我们知道现在的操作系统是分层的&#xff0c;内核封装了与底层的接口&#xff0c;通过系统调用提供给上层应用使用。 当进程运行在内核空间时&#xff0c;它就处于内核态&#xff1b;当进程运行在用户空间时&#xff0c;它就处于用户态。 当我们需要进行IO操…

【小沐学Python】网络爬虫之requests

文章目录 1、简介2、requests方法2.1 get2.2 post 3、requests响应信息4、requests的get方法4.1 url4.2 headers4.3 params4.4 proxies4.5 verify4.6 timeout4.7 cookies4.8 身份验证 3、测试代码3.1 获取网页HTML&#xff08;get&#xff09;3.2 获取网页HTML&#xff08;带he…

【LeetCode热题100】打卡第26天:最大矩形

文章目录 最大矩形⛅前言&#x1f512;题目&#x1f511;题解 最大矩形 ⛅前言 大家好&#xff0c;我是知识汲取者&#xff0c;欢迎来到我的LeetCode热题100刷题专栏&#xff01; 精选 100 道力扣&#xff08;LeetCode&#xff09;上最热门的题目&#xff0c;适合初识算法与数…

随着ChatGPT、文言一心的大火,未来可能的生活工作方式

前面的文章笼统的扯了一些ChatGPT、文言一心的差异化&#xff0c;感觉还是不够明白直观。特地找了一份资料&#xff0c;通过基础能力、进阶能力、和一些垂直领域的几百个各种问题&#xff0c;来对比分析两者的回答情况&#xff0c;让大家可以有个更接地气的了解。 由于问题太多…

无限脉动:释放音乐和区块链在音乐领域的力量

音乐是一种永恒的通用语言&#xff0c;它将人们聚集在一起&#xff0c;超越了边界&#xff0c;在我们灵魂深处产生共鸣&#xff0c;创造联系。在当今数字时代&#xff0c;随着区块链技术和去中心化网络的出现&#xff0c;音乐世界正在经历一场深刻的变革。 我们在与艺术家合作&…

动态规划 DP (二)

3.二维动态规划 1) 力扣https://leetcode.cn/problems/minimum-path-sum/第一行的的路径只与左边的元素有关&#xff0c;第一列的路径只与上面的元素有关。 除了第一行和第一列&#xff0c;其他元素的路径取决于左边和上面元素的最小值。 只要每次都选择值最小的路径&#…

2021电工杯数学建模B题解题思路(光伏建筑一体化板块指数发展趋势分析及预测)

目录 一、前言 二、问题背景 三、具体问题 四、解题思路 &#xff08;一&#xff09;整体思路 &#xff08;二&#xff09;问题一 &#xff08;三&#xff09;问题二 &#xff08;四&#xff09;问题三 &#xff08;五&#xff09;问题四 &#xff08;六&#xff09;…

2023最新谷粒商城笔记之秒杀服务篇(全文总共13万字,超详细)

秒杀服务 秒杀具有瞬间高并发的特点&#xff0c;针对这一特点&#xff0c;必须要做限流异步缓存(页面静态化)独立部署 限流方式&#xff1a; 前端限流&#xff0c;一些高并发的网站直接在前端页面开始限流&#xff0c;例如&#xff1a;小米的验证码设计Nginx 限流&#xff0c…

ChatGPT从入门到精通,深入认识Prompt

ChatGPT从入门到精通&#xff0c;一站式掌握办公自动化/爬虫/数据分析和可视化图表制作 全面AI时代就在转角 道路已经铺好了 “局外人”or“先行者” 就在此刻 等你决定让ChatGPT帮你高效实现职场办公&#xff01;行动起来吧1、ChatGPT从入门到精通&#xff0c;一站式掌握办公…

Unity 中的旋转、targetFrameRate、 vSyncCount、Time

1. 旋转&#xff1a; Unity 中的旋转用eulerAngle 表示&#xff0c;但在内部是以quaternion存储。欧拉角旋转围绕三个轴进行三次独立旋转&#xff0c;依次是z、x、y。To convert from Euler angles to quaternions, you can use the Quaternion.Euler function.To convert a q…

Linux 文件操作

文章目录 一、task_struct 和 file 的关系二、文件操作的系统调用三、进程默认打开的三个文件四、文件重定向五、Linux 下一切皆文件 文件是在磁盘上创建出来的&#xff0c;当我们想进行文件操作时&#xff0c;根据冯诺依曼体系结构&#xff0c;CPU 只和内存交互&#xff0c;为…

【裸机开发】Reset 中断服务函数(汇编实现)

目录 一、Reset 中断服务函数的实现步骤 二、汇编实现 Reset 中断服务函数 1、禁止/打开全局中断 2、设置SP指针 3、清除 .bss 段 4、完整 Reset 中断服务函数 一、Reset 中断服务函数的实现步骤 实现 Reset 中断服务函数的基本步骤如下&#xff1a; 设置各个模式下的S…

关联式容器set和map

文章目录 一.容器二.set的介绍1.insert2.lower_bound&&upper_bound3.find和countfindcount 三. multiset四.map最特别的operator[] 四.multimap&#xff0c;因为允许键值冗余&#xff0c;所以它没有operator[]&#xff0c;它的find返回的是中序遍历第一次遇到的节点五.…

ChatGPT办公自动化实战

ChatGPT从入门到精通&#xff0c;一站式掌握办公自动化/爬虫/数据分析和可视化图表制作 全面AI时代就在转角 道路已经铺好了 “局外人”or“先行者” 就在此刻 等你决定 让ChatGPT帮你高效实现职场办公&#xff01;行动起来吧 1、ChatGPT从入门到精通&#xff0c;一站式掌握办…

对象的销毁

析构函数 C 中的类可以定义一个特殊的清理函数 这个特殊的清理函数叫做析构函数析构函数的功能与构造函数相反 定义&#xff1a;~ClassName() 析构函数没有参数也没有返回值类型声明析构函数在对象销毁时自动被调用 析构函数使用初探 #include <stdio.h>class Test …