类和对象【4】static成员、const对象、友元

news2024/11/24 4:27:06

全文目录

  • 引言
  • static成员
    • static成员变量
    • static成员函数
  • const对象
  • 友元
    • 友元函数
    • 友元类
  • 总结

引言

通过前面的三篇文章,相信大家对类和对象已经有了一个基本的认识。
类和对象1(初识)
类和对象2(默认成员函数)
类和对象3(初始化列表)
但是在前面举的一些例子中不难发现一些漏洞以及许多可以改进的点:

比如一些时候我们需要一些全局的变量来管理许多对象的属性,但是创建全局变量又影响了类封装;
我们知道this指针的类型是T* const 有时我们需要对const修饰的类对象进行例如赋值给别的对象,打印等操作时。this指针的传递就会出现权限放大的问题;
我们有时也需要在类外访问私有成员,正常情况下显然是不允许的。

在本篇文章中就将继续补充类和对象的知识:

static成员

我们知道,类对象是存储在栈区中的,我们可以计算一个简单的类的大小:

class A
{
private:
	char _a;
	int _b;
	int _c;
};
int main()
{
	A a;
	cout << sizeof(a) << endl;
	return 0;
}

在这里插入图片描述
根据内存对齐,不难计算出这个A类的大小为12字节。
这三个成员变量_a、_b、_c都是属于某个对象的属性,类实例化时被定义。当然不能在类外访问,也不具有全局的属性。

static成员变量

但是static变量是存储在静态区的,它虽然封装在类中(只在类类型中声明),但不属于某个对象。
对于某个类类型而言,static成员只是在类中声明,在类外定义,定义时不添加static关键字,不占用该类型对象的空间

class A
{
private:
	char _a;
	int _b;
	int _c;
	static int a;
};
int A::a = 10;

int main()
{
	A a;
	cout << sizeof(a) << endl;
	return 0;
}

在这里插入图片描述
这个static成员变量就类似于封装在类中的全局变量。虽然不能在类外面访问,但是可以在类中起到全局变量类似的作用来反映这个类类型的许多对象的属性。

static成员函数

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

static成员函数与一般成员函数不同,它没有隐含的this指针的传参,因此不能访问私有的成员变量。但是它可以正常访问static成员变量

class A
{
public:
	static void fun()
	{
		//_a++; 错误代码:非静态成员引用必须与特定对象相对
		cout << a++ << endl;
	}
private:
	char _a;
	int _b;
	static int a;
};
int A::a = 10;

访问static成员函数时,可以通过对象名.函数调用访问,也可以通过类类型名::函数调用访问

class A
{
public:
	static void fun()
	{
		//_a++; 错误代码:非静态成员引用必须与特定对象相对
		cout << a++ << endl;
	}
private:
	char _a;
	int _b;
	static int a;
};
int A::a = 10;

int main()
{
	A a;
	a.fun();
	A::fun();
	return 0;
}

在这里插入图片描述
之前提过,调用成员函数其实是代替某个对象调用成员该成员函数。这里就有一个前提,即在调用成员函数时,一定有一个对象主体是已经定义过的,所以一般的成员函数隐式传this指针访问私有成员变量当然是可以的;

但是对于static成员函数而言,我们调用static成员函数时却没有已经实例化对象的前提(可以通过类型名调用)。所以不能隐式的this传参,自然也就不能访问私有的成员变量。而static成员变量虽然在类中声明,但是不随实例化定义,所以自然可以当其在外部定义后在函数中访问。

const对象

在前面我们简单的实现过一些成员函数,例如日期类加日期的函数、打印函数。对于普通的类对象当然是适合的:

class Date
{
public:
	Date(int year = 2023, int month = 2, int day = 10)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
	int GetMonthDay(int year, int month);
	Date& AddDate(int day);
	void print();
private:
	int _year;
	int _month;
	int _day;
};
void Date::print()
{
	cout << _year << " " << _month << " " << _day << endl;
}

int main()
{
	Date d1;
	d1.print();
	return 0;
}

在这里插入图片描述
但当我们实例化一个const Date型的类对象时,这个const对象就不能调用print函数来打印日期了:

int main()
{
	Date d1;
	d1.print();
	const Date d2;
	//d2.print();  错误代码:不能将“this”指针从“const Date”转换为“Date&“
	return 0;
}

因为this指针的类型是Date* const,当对这个可更改指向的之的指针传const对象时,就会发生权限放大的问题,这当然是不允许的。
面对这种问题,我们就需要给this指针加上const修饰,使其的类型为const Date* const。但是this指针是隐式传参的,所以我们不能按照以前的方式传const型指针。

C++提供了用const修饰this指针的方法,即在参数列表后加上const

class Date
{
public:
	Date(int year = 2023, int month = 2, int day = 10)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
	int GetMonthDay(int year, int month);
	Date& AddDate(int day);
	void print() const;
private:
	int _year;
	int _month;
	int _day;
};
void Date::print() const
{
	cout << _year << " " << _month << " " << _day << endl;
}

int main()
{
	Date d1;
	d1.print();  //权限缩小
	const Date d2(2023, 5, 19);
	d2.print();  //权限平移
	return 0;
}

在这里插入图片描述
这样就可以实现const对象的this传参了。

友元

我们有时会需要在类外访问私有成员函数友元提供了一种突破封装的方式,提供了便利
但是友元的过多使用一定会破坏封装,所以不宜多用!

友元函数

友元函数即可以使用friend关键字使一个在外部声明的函数作为类的友元函数。这样,这个友元函数就可以访问类的私有成员:

class A
{
	friend void func1(A&);
private:
	int _a;
};
void func1(A& a)
{
	cout << a._a << endl;
}

需要注意的是:

  1. 友元函数可访问类的私有和保护成员,但不是类的成员函数(没有this指针传参)
  2. 友元函数不能用const修饰;
  3. 一个函数可以是多个类的友元函数;
  4. 友元函数的调用与普通函数的调用原理相同
  5. 友元函数可以在类定义的任何地方声明,不受类访问限定符限制;
  6. 需要在类内部的任何位置,加上friend修饰声明该外部函数(friend在函数声明的返回值前)。

(在下一篇文章中将介绍一个友元函数的应用)

友元类

与友元函数类似,friend关键字也可以声明一个外部的类作为某类的友元类,友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。

class A
{
	friend void func1(A&);
	friend class B;
private:
	int _a;
};
void func1(A& a)
{
	cout << a._a << endl;
}

class B
{
public:
	void func1(A& a)
	{
		cout << a._a << endl;
	}
private:
	int _b;
};

需要注意的是:

  1. 友元关系不具有交换性
    比如上述A类和B类,在A类中声明B类为其友元类,那么可以在B类中直接访问A类的私有成员变量,但想在A类中访问B类中私有的成员变量则不行。
  2. 友元关系不能传递
    如果C是B的友元, B是A的友元,则不能说明C时A的友元。
  3. 友元关系不能继承:后面再详细介绍。

总结

到此,关于类和对象的所有基础知识就介绍完了
接下来将会使用前面的知识来举例实现一个日期类。相信大家会对类和对象有更好的理解,欢迎持续关注哦

如果大家认为我对某一部分没有介绍清楚或者某一部分出了问题,欢迎大家在评论区提出

如果本文对你有帮助,希望一键三连哦

希望与大家共同进步哦

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

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

相关文章

数据结构与算法11:堆

目录 【堆】 堆中插入和删除元素 堆排序 【堆的常见应用】 应用1&#xff1a;优先级队列 &#xff08;1&#xff09;合并有序小文件 &#xff08;2&#xff09;定时器功能 应用2&#xff1a;计算排行榜中前K个数据 应用3&#xff1a;求中位数 应用4&#xff1a;计算…

算法基础--MD5算法介绍

1、简介 MD5再开发过程中经常碰到的一种算法&#xff0c;因此感觉有必要对其原理进行更深入的了解一下。 2、算法概念 散列函数&#xff0c;也称作哈希函数&#xff0c;消息摘要函数&#xff0c;单向函数或者杂凑函数。散列函数主要用于验证数据的完整性。通过散列函数&#x…

自然语言处理从入门到应用——自然语言处理的应用任务

分类目录&#xff1a;《自然语言处理从入门到应用》总目录 本文介绍信息抽取、情感分析、问答系统、机器翻译和对话系统等自然语言处理应用任务。这些任务可以直接或间接地以产品的形式为终端用户提供服务&#xff0c;是自然语言处理研究应用落地的主要技术。 信息抽取 信息抽…

天气预报信息获取程序--GUI--可以使用

上次正对项目中需要填写项目日志&#xff0c;制作了一个命令行版本的下载天气信息的程序&#xff0c;满足日常需要&#xff0c;调整一下界面版本的程序 如果大家使用命令行的可以使用下面的版本&#xff08;连接&#xff09; https://ht666666.blog.csdn.net/article/details…

逻辑漏洞学习-知识点总结

逻辑漏洞就是程序在实现业务逻辑上存在的错误&#xff0c;辑漏洞的出现通常是因为程序在设计业务逻辑时考虑不够全面&#xff0c;或者程序员的思维过程存在瑕疵&#xff0c;没有充分考虑到各种可能的情况 大部分程序员在设计的时候&#xff0c;目标是实现功能需求&#xff0c;…

Linux基础知识点 有这篇就足够了!!

❄️作者介绍&#xff1a;奇妙的大歪❄️ &#x1f380;个人名言&#xff1a;但行前路&#xff0c;不负韶华&#xff01;&#x1f380; &#x1f43d;个人简介&#xff1a;云计算网络运维专业人员&#x1f43d; 目录 一、 从认识操作系统开始 1.1 操作系统简介 1.2 操作系统…

chatgpt赋能Python-python分表

介绍 Python是一种流行的编程语言&#xff0c;适用于各种应用程序开发&#xff0c;包括网络应用程序、数据库应用程序以及数据分析和科学计算。Python分表是基于Python编写的分表工具&#xff0c;可以帮助开发人员更轻松地管理大型数据库表格。 Python分表是如何工作的&#…

0219-810

3GPP TS 02.19 V8.1.0 (2005-06) 前言 本技术规范由第三代合作伙伴计划 (3GPP) 制定。 本文件的内容取决于 TSG 的持续工作&#xff0c;并可能在 TSG 正式批准后发生变化。 如果 TSG 修改本文档的内容&#xff0c;TSG 将重新发布 确定发布日期的变化和版本号的增加如下&…

低代码开发平台选择指南:如何选出最适合企业的低代码平台?

低代码平台的兴起改变了公司处理软件开发的方式。这些平台使组织能够快速高效地构建应用程序&#xff0c;该应用程序可以利用预设组件和开箱功能。但是&#xff0c;因为有这么多低代码平台可以使用&#xff0c;所以为你的组织选择合适的平台可能是一个挑战。本文将探索如何低代…

FreeRTOS任务切换

PendSV异常 SVC 用于产生系统函数的调用请求。例如&#xff0c;操作系统不让用户程序直接访问硬件&#xff0c;而是通过提供一些系统服务函数&#xff0c;用户程序使用 SVC 发出对系统服务函数的呼叫请求&#xff0c;以这种方法调用它们来间接访问硬件。因此&#xff0c;当用户…

(字符串 ) 459. 重复的子字符串——【Leetcode每日一题】

❓459. 重复的子字符串 难度&#xff1a;简单 给定一个非空的字符串 s &#xff0c;检查是否可以通过由它的一个子串重复多次构成。 示例 1: 输入: s “abab” 输出: true 解释: 可由子串 “ab” 重复两次构成。 示例 2: 输入: s “aba” 输出: false 示例 3: 输入: s “…

IDEA+Mysql调试常见异常解决办法_kaic

IDEA导入项目出现Error: java: 程序包javax.servlet.http不存在错误的解决办法 解决方法&#xff1a;打开File>Project Structure>Libraries&#xff0c;点击右侧加号&#xff0c;寻找到tomcat的lib文件夹&#xff0c;点击ok&#xff0c;IDEA会自动重新Rebuild Project&…

数据结构 | 图的深度优先遍历和广度优先遍历(C语言)

一、数据结构定义 1、图 #define MaxVertexNum 100 // 最大可存储的节点数目/*图*/ typedef char VexterType; typedef int EdgeType;typedef struct GraphMatrix {VexterType Vexs[MaxVertexNum]; //结点 EdgeType Edges[MaxVertexNum][MaxVertexNum]; //边int vexnum, a…

使用 MCSM 面板一键搭建我的世界服务器,并内网穿透公网远程联机

文章目录 前言1.Mcsmanager安装2.创建Minecraft服务器3.本地测试联机4. 内网穿透4.1 安装cpolar内网穿透4.2 创建隧道映射内网端口 5.远程联机测试6. 配置固定远程联机端口地址6.1 保留一个固定TCP地址6.2 配置固定TCP地址 7. 使用固定公网地址远程联机 转载自远程穿透文章&…

【AI】Stable-Diffusion-WebUI使用指南

注&#xff1a;csdn对图片有审核&#xff0c;审核还很奇葩&#xff0c;线稿都能违规&#xff0c;为保证完整的阅读体验建议移步至个人博客阅读 最近AI绘画实现了真人照片级绘画水准&#xff0c;导致AI绘画大火&#xff0c;公司也让我研究研究&#xff0c;借此机会正好了解一下…

图像处理:GrapeCity Documents Imaging 6.1.2 Crack

适用于 .NET 6 的快速、强大的映像 API 库,在代码中应用高级图像处理&#xff0c;零依赖关系。 加载和保存图像文件&#xff0c;如BMP&#xff0c;JPEG&#xff0c;TIFF&#xff0c;GIF&#xff0c;ICO&#xff0c;SVG&#xff0c;WebP和PNG 对灰度和 RGB 图像应用抖动和阈值等…

Ribbon 负载均衡策略 —— 图解、源码级解析

文章目录 负载均衡策略RandomRuleRoundRobinRuleRetryRuleWeightedResponseTimeRuleBestAvailableRuleAvailabilityFilteringRuleZoneAvoidanceRule Ribbon 负载均衡策略源码RandomRule源码RoundRobinRule源码BestAvailableRule源码RetryRule源码 通过本文你可以学习到&#xf…

自学大语言模型之BERT

BERT 模型由 Jacob Devlin、Ming-Wei Chang、Kenton Lee 和 Kristina Toutanova在BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding中提出。它是一种双向变换器&#xff0c;使用掩码语言建模目标和对包含多伦多图书语料库和维基百科的大型语…

开源高星精选,10个2023企业级Python测试项目,再不学习时间就没了

纸上得来终觉浅&#xff0c;光学习理论知识是不够的。 想要学好软件测试必须要结合实战项目深入掌握&#xff0c;今天给大家分享十个2022最新企业级Python软件测试项目&#xff1a; ​ 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; ▌Rank 1&#xf…

SEW-Movifit软件的调试步骤

首先安装软件&#xff08;名称和版本为SEW_Software_MotionStudio_V5-9-0-4-compact&#xff09;。安装完毕后打开软件&#xff0c;新建一个工程。 3、新建完成之后会进入如下画面。 4、点击红框内的图标进行设置 5、打开后会显示如下画面&#xff0c;在下拉菜单中选择serial这…