首页 > 编程语言 >[C++ 从入门到精通] 15.友元函数、友元类、友元成员函数

[C++ 从入门到精通] 15.友元函数、友元类、友元成员函数

时间:2023-12-28 14:31:59浏览次数:27  
标签:友元 15 函数 成员 private include 友元类



文章预览:

  • 一. 前言
  • 二. 友元函数
  • 三. 友元类
  • 四. 友元成员函数



一. 前言

众所周知,C++控制对类对象私有成员的访问。通常,公有类方法(public)提供唯一的访问途径,但是有时候这种限制太严格,以至于不适合特定的编程问题。

在这种情况下,C++提供了另外一种形式的访问权限:友元,友元有3种:

  • 友元函数;
  • 友元类;
  • 友元成员函数;

优缺点

  • 优点:通过让函数成为类的友元(即:友元函数),可以赋予该函数与类的成员函数相同的访问权限,使其可以访问本类protected、private成员,在某些频繁访问成员变量的地方可以提高性能。
  • 缺点:友元破坏了面向对象的封装性。

二. 友元函数

1、通过friend将一个函数(友元函数是个函数)声明为某个类的友元函数,那么该函数就能访问这个类的所有成员(成员变量、成员函数),无论是public,private,protected

2、因为友元函数不属于类成员,所以其不受public/protected/private的限制,放在public/protected/private下声明都行。

代码展示

#include <iostream>
using namespace std;

class A
{
private:
	int data;

	void display(){
		cout << "data = " << data << endl;
	}

	friend void change(int x, A& a); // 将函数change()声明为类A的友元函数
};

void change(int x, A& a)
{
	a.data = x;
	a.display();
}

int main()
{
	A a;
	change(10, a);
	return 0;
}

三. 友元类

1、可以在类A中把类B声明为类A的友元类,此时,在类B(类A的友元类)的成员函数中,可以访问类A的所有成员(成员变量、成员函数),无论是public,private,protected

2、由于友元类不属于类成员,所以友元类的声明不受public、protected、private的影响。

代码展示Tip:为什么需要类B的声明):

#include <iostream>
using namespace std;

class B; // 类B的声明,类A用到了类B,而类B的定义有可能在类A的定义之后导致编译出错,所以最好先声明一下类B
class A
{
private:
	int data;

	void display()
	{
		cout << "data = " << data << endl;
	}

	friend class B; // 将类B声明为类A的友元类(用到了类B的名字,所以需要前面声明一下class B; )
};

class B
{
public:
	void change(int x, A& a)
	{
		a.data = x;  //在类B(类A的友元类)的成员函数中,可以访问类A的所有成员(成员变量、成员函数),无论是public,private,protected
		a.display();
	}
};

int main()
{
	A a;
	B b;
	b.change(50, a);

	return 0;
}

注意:每个类都负责控制自己的友元类和友元函数:

  • 友元关系不能被继承;
  • 友元关系是单向的,比如类B是类A的友元类,但这并不代表类A是类B的友元类;
  • 友元关系没有传递性,比如类B是类A的友元类,类C是类B的友元类,但这并不代表类C是类A的友元类;

四. 友元成员函数

友元成员函数:即是本类的成员函数,又是其他类的友元函数。

代码展示

A.h(Tip:为什么使用#include "B.h"而不用class B;声明类B

#ifndef __A_H
#define __A_H

#include <iostream>

//class B;   //注:声明友元成员函数不能仅仅使用类B的声明了,因为在friend void B::change(int x, A& a)不仅仅用到了类B的名字,
             //还用到了其成员函数change(),系统需要先判断类B中是否有其成员函数change(),所以需要用#include "B.h"
#include "B.h"
             
class A
{
private:
	int data;

	void display()
	{
	    std::cout << "data = " << data << std::endl;
	}

	friend void B::change(int x, A& a); // 该函数是友元成员函数的声明:将类B的成员函数change()声明为类A的友元函数
};

#endif

B.h

#ifndef __B_H
#define __B_H

class A; // 类A的声明

class B
{
public:
	void change(int x, A& a); // 只有public的成员函数才能成为其它类的友元函数
};

#endif

B.cpp

#include "A.h"
#include "B.h"

void B::change(int x, A& a)
{
	a.data = x;
	a.display();
}

main.cpp

#include "A.h"
#include "B.h"

int main()
{
	A a;
	B b;
	b.change(50, a);

	return 0;
}

下雨天,最惬意的事莫过于躺在床上静静听雨,雨中入眠,连梦里也长出青苔。


标签:友元,15,函数,成员,private,include,友元类
From: https://blog.51cto.com/u_16436086/9014830

相关文章

  • PHP查询内存占用函数
    PHP查询内存占用函数memory_get_usage()在PHP中,包括ThinkPHP框架中,直接查询一个数组占用的内存大小可以使用memory_get_usage()函数。这个函数返回当前PHP脚本消耗的内存总量(以字节为单位)。以下是一个简单的示例,展示如何在ThinkPHP中获取一个数组占用的内存大小://在ThinkPHP......
  • 文心一言 VS 讯飞星火 VS chatgpt (158)-- 算法导论12.3 5题
    五、用go语言,假设为每个结点换一种设计,属性x.p指向x的双亲,属性x.succ指向x的后继。试给出使用这种表示法的二叉搜索树T上SEARCH、INSERT和DELETE操作的伪代码。这些伪代码应在O(h)时间内执行完,其中h为树T的高度。(提示:应该设计一个返回某个结点的双亲的子过程。......
  • 【flink番外篇】5、flink的window(介绍、分类、函数及Tumbling、Sliding、session窗口
    文章目录Flink系列文章一、maven依赖二、示例:基于数量的滚动窗口与滑动窗口1、滚动窗口实现地铁进站口人数1)、实现2)、验证步骤2、滑动窗口实现地铁进站口人数1)、实现2)、验证步骤三、示例:会话窗口1、实现2、验证步骤本文介绍了Flinkwindow基于数量的滚动、滑动窗口和会话窗口示......
  • 【flink番外篇】5、flink的window(介绍、分类、函数及Tumbling、Sliding、session窗口
    文章目录Flink系列文章一、Flink的window介绍1、window介绍2、windowAPI1)、WindowAssigner2)、Trigger3)、Evictor3、window的生命周期二、window的分类1、TumblingWindows2、SlidingWindows3、SessionWindows4、GlobalWindows5、按照时间time和数量count分类6、按照滑动间隔s......
  • 【flink番外篇】5、flink的window(介绍、分类、函数及Tumbling、Sliding、session窗口
    文章目录Flink系列文章一、maven依赖二、示例:基于时间的滚动和滑动窗口1、滚动窗口实现统计地铁进站口人数1)、一般实现(Tuple2数据结构)及验证2)、面向对象实现(pojo数据结构)及验证3)、面向对象lambda实现(pojo的数据结构lambda)及验证4)、一般lambda实现(Tuple2数据结构)及验证2、滑动窗口......
  • 【flink番外篇】5、flink的window(介绍、分类、函数及Tumbling、Sliding、session窗口
    文章目录Flink系列文章一、Flink的window介绍1、window介绍2、windowAPI1)、WindowAssigner2)、Trigger3)、Evictor3、window的生命周期二、window的分类1、TumblingWindows2、SlidingWindows3、SessionWindows4、GlobalWindows5、按照时间time和数量count分类6、按照滑动间隔s......
  • Postgresql中PL/pgSQL的游标、自定义函数、存储过程的使用
    场景Postgresql中PL/pgSQL代码块的语法与使用-声明与赋值、IF语句、CASE语句、循环语句:Postgresql中PL/pgSQL代码块的语法与使用-声明与赋值、IF语句、CASE语句、循环语句上面讲了基本语法,下面记录游标、自定义函数、存储过程的使用。注:博客:霸道流氓气质_C#,架构之路,SpringBoot实......
  • 内置函数
    内置函数一、数据类型转换(8个)强制类型转换的方法:强转成字符串(str())强转成整数(int())强转成浮点数(float())强转成布尔类型(bool())强转成列表类型(list())强转成元组类型(tuple())强转成集合类型(set())强转成字典类型(dict())二、进制转换(3个)#十进制转二进制,0b开......
  • Oracle 中 LISTAGG 函数的介绍以及使用
    LISTAGG函数介绍listagg函数是Oracle11.2推出的新特性。其主要功能类似于wmsys.wm_concat函数,即将数据分组后,把指定列的数据再通过指定符号合并。LISTAGG使用listagg函数有两个参数: 1、要合并的列名 2、自定义连接符号☆LISTAGG函数既是分析函数,也是聚......
  • lightdb/postgresql中plpgsql、函数与操作符、表达式及其内部实现
    PG_PROCPG_OPERATORpg_opclass用于定义索引上的相关操作符,一般来说是同一类数据类型。pg_opfamiliy定义了相互兼容的数据类型的操作符,关系见https://www.postgresql.org/docs/9.1/catalog-pg-opclass.html。pg8.3引入pg_opfamilies,原因:Create "operatorfamilies" toimprove......