C++类和对象-5

news2024/11/23 7:46:41

本篇博客来讲述C++类和对象中的最后一些内容,即友元和const的使用方法。

目录

1.友元

1.1引入

1.2内容

1.2.1友元函数

1.2.2友元类

1.3内部类

2.const修饰

2.1内容

2.1.1常数据成员

2.1.2常成员函数

2.1.3常对象

2.2示例

1.友元

1.1引入

在讲述友元之前,我们来简单了解一下友元诞生的原因。当我们封装类后,对于其中私有成员的访问我们需要提供具体接口来返回,这样我们才可以在外部对类中的私有成员进行访问,如下所示代码:

#include<iostream>

#define Pi 3.14

class Circle {
private:
	//圆心坐标
	int x;
	int y;
	//半径
	int r;
public:
	Circle(int x = 0, int y = 0, int r = 0) {
		this->x = x;
		this->y = y;
		this->r = r;
	}
	int Get_r() {//提供对外接口用于访问类中对应私有成员
		return r;
	}
};

double SquareMeasure(Circle& c1) {
	return c1.Get_r() * c1.Get_r() * Pi;
}

int main() {
	Circle c1(0, 0, 1);
	std::cout << SquareMeasure(c1);
	return 0;

其中Get_r接口便是提供的对外访问类中私有成员的接口,不过在具体的SquareMeasure函数中我们对于Get_r接口调用次数较为重复,降低了程序的执行效率,所以在此基础上,提出友元的概念。

1.2内容

1.2.1友元函数

友元提供了一种突破封装的方式,有时会为我们提供一定程度的便利。但是友元在另一种程度上会增加代码的耦合性,破坏了原有的封装,对于其具体的使用方式我们在上述代码的基础上改变。

#include<iostream>

#define Pi 3.14

class Circle {
private:
	//圆心坐标
	int x;
	int y;
	//半径
	int r;
public:
	Circle(int x = 0, int y = 0, int r = 0) {
		this->x = x;
		this->y = y;
		this->r = r;
	}
	friend double SquareMeasure(Circle& c1);
};

double SquareMeasure(Circle& c1) {
	return c1.r * c1.r * Pi;
}

int main() {
	Circle c1(0, 0, 1);
	std::cout << SquareMeasure(c1);
	return 0;
}

我们在Circle类中声明SquareMeasure函数为友元,则在接下来的SquareMeasure函数中,我们可以直接访问Circle类中的私有数据成员,并且在使用过程中,它存在几种特征:

  • 友元函数不是当前类中的成员函数,而是独立于当前类的外部函数,但他可以访问类中的所有成员;
  • 友元函数可以在类定义的任何地方声明,不受访问限定符限制;
  • 友元函数可以定义在类的内部,也可以定义在类的内部。
  • 友元函数不能使用const修饰;
  • 一个函数可以是多个类的友元函数;
  • 友元函数的调用和普通函数的调用原理相同。

1.2.2友元类

friend关键字除修饰函数之外,还可以用于修饰类,被修饰的类则称之为友元类。友元类中的所有成员函数都可以是另一个类的友元函数,都可以访问一个类中的非共有成员。

 同样的,我们借助具体的代码来进行展示和理解:

#include<iostream>

#define Pi 3.14

class Circle {
private:
	//圆心坐标
	int x;
	int y;
	//半径
	int r;
	friend class Size;
public:
	Circle(int x = 0, int y = 0, int r = 0) {
		this->x = x;
		this->y = y;
		this->r = r;
	}
};

class Size {
private:
	double c;//周长
	double s;//面积
public:
	Size(Circle& c1) {
		c = 2 * Pi * c1.r;
		s = c1.r * c1.r * Pi;
	}
	void CircleShow() {
		std::cout << "周长:" << c << std::endl;
		std::cout << "面积:" << s << std::endl;
	}
};


int main() {
	Circle c1(0, 0, 1);
	Size c2(c1);
	c2.CircleShow();
	return 0;
}

很直观,Size类是Circle类的友元,我们可以在Size类中直接访问Circle类中的私有成员,在使用过程中,它存在以下几种特征:

  • 友元关系是单向的,不具有交换性,即在上述案例中我们可以在Size类中直接访问Circle类中的私有成员,但是无法在Circle类中访问Size类的私有成员;
  • 友元关系不具备传递性,即如果B是A的友元,C是B的友元,但是C并不是A的友元;
  • 友元关系并不能继承,即B是A的友元,C继承于A,但是B并不是C的友元。

1.3内部类

当存在一个类直接定义在另一个类的范围,则该类被称之为内部类。内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员,外部类并不具备对内部类的优越访问权限。

不过,内部类是外部类的友元,内部类可以通过外部类的对象参数来访问外部类中的所有成员,但外部类并不是内部类的友元,我们来看代码:

#include<iostream>

class A {
private:
	int k;
public:
	A(int k = 0) {
		this->k = k;
	}
	class B {//内部类B天生便是外部类A的友元
	public:
		void Show(const A& a1) {
			std::cout << a1.k;
		}
	};
};

int main() {
	A::B a2;
	a2.Show(A());
	return 0;
}

注意在定义B类对象时,加上具体的作用域限定符。内部类的特征我们可以总结为以下几点:

  • 内部类有定义在外部类的任何地方,不受访问限定符限制;
  • 内部类可以直接访问外部类中的static成员,不需要外部类的对象或是类名;
  • sizeof(外部类),只和外部类有关,和内部类无关。

2.const修饰

2.1内容

对于一些数据我们在进行共享的同时,并不希望它们发生改变,于是我们可以加入const修饰来对这些数据进行保护,使其变为常量,常量在程序运行过程中是不允许改变的。

我们根据const修饰的内容不同,可以将其分为三类,分别是:

  • 常数据成员--const修饰数据成员;
  • 常成员函数--const修饰成员函数;
  • 常对象--const修饰类的对象。

2.1.1常数据成员

在类中定义了常数据成员,则构造函数只能通过初始化列表对其进行初始化,并且其他函数都不能对常数据成员进行修改,只能进行访问。

2.1.2常成员函数

常成员函数的原型进行声明时,我们需要在其函数定义的首部使用关键字从const,并且常成员函数不能修改本类的数据成员,也不能调用普通的成员函数,这样可以保证在常成员函数当中不会修改数据成员的值。(关键字const可以当作函数重载的标志)

2.1.3常对象

常对象必须在定义时进行初始化,并且初始化之后的数据不能被更新,不能被改变,因此通过常对象只能调用常成员函数,而不能调用类中的其他普通成员函数。

2.2示例

#include<iostream>

using namespace std;

class Date
{
public:
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << "Print()" << endl;
		cout << "year:" << _year << endl;
		cout << "month:" << _month << endl;
		cout << "day:" << _day << endl << endl;
	}
	void Print() const
	{
		cout << "Print()const" << endl;
		cout << "year:" << _year << endl;
		cout << "month:" << _month << endl;
		cout << "day:" << _day << endl << endl;
	}
private:
	int _year; // 年
	int _month; // 月
	int _day; // 日
};

void Test() {
	Date d1(2022, 1, 13);

	d1.Print();

	const Date d2(2022, 1, 13);

	d2.Print();
}

int main() {
	Test();
	return 0;
}

对于上面代码的执行结果为:

我们可以发现结果的执行结果如函数重载时的模样。

这是因为当我们在使用const修饰成员函数之后,编译器会自动将其优化成如下情况:

	void Print(const Date* this) {

	}

 即默认的this指针加入const修饰,进而形成重载。

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

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

相关文章

使用DR对流量进行管理 subnet子集的定义

这里vs可以控制往svc1和svc2流量走的比例&#xff0c;但是这里只假设往svc3里面走。现在想控制的是往pod1和pod2各走多少流量。 流量到了svc3的时候还是使用的是kube-proxy对流量进行转发。 了解DR DR定义的是经过VS之后已经到达service的流量&#xff0c;主要可以用于&#xf…

【深度学习入门:基于Python的理论与实现】

文章目录 神经网络从感知机到神经网络神经网络的例子复习感知机激活函数登场 激活函数sigmoid函数阶跃函数的实现sigmoid函数的实现 sigmoid函数和阶跃函数的比较ReLU函数 3层神经网络的实现符号确认代码实现 输出层的设计恒等函数和softmax函数输出层的神经元数量 手写数字识别…

【ArcGIS Pro二次开发】(36):度分秒转十进制度

经纬度坐标的表达方式比较常用的一般有2种&#xff0c;【度分秒和十进制度】。 在成果展示中&#xff0c;以【度分秒】居多&#xff0c;但如果要将坐标导入ArcGIS中&#xff0c;则一般需要用到【十进制度】&#xff0c;这个转换可以在Excel中进行&#xff0c;也可以在ArcGIS中的…

火龙果MM32F3273G8P开发板MindSDK开发教程4 - 滴嗒定时器Systick的配置

火龙果MM32F3273G8P开发板MindSDK开发教程4 - 滴嗒定时器Systick的配置 1、Systick寄存器 Systick是ARM内核的一个外设&#xff0c;所以在不同芯片的代码上移植比较方便&#xff0c;他总共有4个寄存器&#xff0c; 从Systick定义中可以看到&#xff1a; typedef struct {__I…

Android系统的启动流程(二):SystemServer处理过程

Android系统的启动流程&#xff08;二&#xff09;&#xff1a;SystemServer处理过程 摘要 在上篇文章中&#xff0c;我们已经将启动的进程推进到了ZygoteInit的main中&#xff0c;在ZygoteInit中我们已经知道它的main方法中的forkSystemServer方法将会启动系统服务&#xff0…

机器学习 | 支持向量机SVM | 概念了解向

概念了解向&#xff0c;参考视频&#xff1a; 【小萌五分钟】机器学习 | 支持向量机 SVM &#x1f4da;最大间隔分类器 如下图有两种不同颜色的点。我需要一个分类器告诉我&#xff0c;假设在下图中新加入一个点&#xff0c;应该将它分类至红点还是蓝点。考虑加入一条决策边界…

【4 微信小程序学习 - WXSS-WXML-WXS语法】

1 WXSS相关 1 小程序样式的写法 2 WXSS支持的选择器 3 wxss的扩展 – 尺寸单位RPX rpx是为了屏幕自适应. 4 逻辑判断 wx:if – wx:elif – wx:else 对应v-if <!-- 2.条件判断 --> <view wx:if"{{score > 90}}">优秀</view> <view wx:…

程序员兼职接单的平台列表

最近有很多程序员朋友说想要找一份合适的兼职工作&#xff0c;却苦于找不到一个正规靠谱的平台。今天我特意整理了一份超详尽的程序员兼职接单平台list&#xff0c;各位可以按需选择&#xff0c;也希望大家都能找到心仪的工作~ 中高端开发者必备的兼职接单平台&#xff1a;程序…

Ubuntu 登录提示信息`Message of The Day`(MOTD)定制与开关

一、效果 登录Ubuntu的时候&#xff0c;在控制台可能会弹出一系列提示消息&#xff0c;有欢迎消息、系统信息、更新信息等等&#xff1a; 这些提示消息被称为Message of The Day&#xff0c;简称MOTD。 Ubuntu与其它Linux版本不太一样&#xff0c;它引入了MOTD 的概念。 这些…

如何使用SonarQube+ SonarScanner分析项目

前言&#xff1a; 六一儿童节要玩程序员的玩具&#xff0c;动手试一试挺有意思的 目录 1. 安装sonarqube 2. 获取Sonarqube令牌 3. 下载安装SonarScanner 5. SonarScanner分析项目 7. 查看分析结果 8.常见问题 版本信息&#xff1a; Sonarqube7.6Sonar-scanner-4.8.0 …

[操作系统]关于进程的管理

首先注明:仍然是复习阶段,所以和课本可能有些许冲突和不同,只是图谱来自于王道考研2022操作系统,旨在快速梳理操作系统的基本知识 1.进程的定义,概念和特征: 多道程序环境下,多个程序并发执行,因此他们将会失去封闭性,不适宜于管理,所以引入了进程这种概念. 进程是程序的一次…

Python自动化测试:pytest实现关键字驱动

在上一篇文章中&#xff0c;我编写了一个非常简单的关键字驱动程序&#xff0c; 不过这个程序只是跑通了功能&#xff0c;还有很多可以优化的地方&#xff0c;这篇文章我想通过 pytest 来简化自动化测试用例的编写&#xff0c;使用的是比较基础的 pytest 功能。 下篇文章我再写…

spark安装部署

spark安装部署 需要指导私信 所有节点安装scala&#xff0c;安装scala需要安装openjdk-8-jre&#xff08;当前用户如果没有sudo权限可将其加入sudo组里&#xff09;,以ubuntu2204-LTS为例&#xff1a; $ sudo apt update $ sudo apt-get install openjdk-8-jre-headless -y (红…

【03Eclipse 窗口说明】对每个窗口和视图的功能和用途的详细说明导航栏编辑器窗口项目资源管理器

Eclipse 窗口说明 简介 Eclipse 是一款功能强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;提供了丰富的窗口和视图来支持开发工作。本教程将详细介绍 Eclipse 主要窗口和常见视图的功能和用途。 主要窗口 1. 导航栏 导航栏位于 Eclipse 窗口的顶部&#xff0…

Java学习路线(22)——测试框架Junit

一、单元测试概念 单元测试就是针对最小的功能单元编写测试代码&#xff0c;Java程序最小的功能单元是方法&#xff0c;因此&#xff0c;单元测试就是针对Java方法的测试&#xff0c;进而检查方法正确性。 二、Junit测试框架 &#xff08;一&#xff09;概念&#xff1a; Jun…

认识、使用 yarn

概念 npm 是前端开发过程中常常使用的命令&#xff0c;比如构建 Vue 项目&#xff0c;亦或下载 Vue 项目依赖但是该命令效率低下&#xff0c;且容易出错&#xff0c;有没有更好的解决方案呢?有&#xff0c;Yarn ta是一个快速、可靠且安全的 JS 包管理工具: 快速:Yamn 本地缓…

黑客松指南|如何快速注册参与Sui x KuCoin Labs Hackathon

由Sui和KuCoin Labs联合主办的夏季黑客松&#xff0c;将为开发者、设计师、创业者和区块链爱好者提供一个交流和合作的平台。参与者将有机会利用Sui的先进技术和KuCoin Labs的资源&#xff0c;开发创新的区块链应用和解决方案。 我们鼓励参与者围绕「基础设施和工具」、「NFT、…

如何使用Jemeter对HTTP进行接口压测?没有比这个更详细的教程

目录 前言 1、首先添加一线程组 2、因为是对HTTP接口进行压力测试&#xff0c;所以需要在线程组下添加一HTTP请求&#xff08;通过鼠标右键->添加->Sampler->HTTP请求 完成&#xff09; 3、紧接着就是对HTTP请求进行设置了&#xff0c;主要设置服务器名称或IP&#…

10年心路历程:一个女测试工程师功能测试转向自动化测试/开发

十年测试心路历程&#xff1a; 由于历史原因&#xff0c;大部分测试人员&#xff0c;最开始接触都是纯功能界面测试&#xff0c;随着工作年限&#xff0c;会接触到一些常用测试工具&#xff0c;比如抓包&#xff0c;数据库&#xff0c;linux等。 我大学学的计算机专业&#xff…

【力扣刷题 | 第四天】 1.两数之和 454.四数之和

1. 两数之和 - 力扣&#xff08;LeetCode&#xff09; 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同…