C++友元函数

2023-11-08

友元——让函数或者类作为另外一个类的朋友,则可以访问当前类的private或者protected

友元friend机制允许一个类授权其他的函数访问它的非公有成员

友元声明以关键字friend开头,它只能出现在类的声明中,它们不受其在类体中的public、private和protected区的影响

一、友元函数可分为以下三种类型:

1、外部函数友元

一个普通函数作为类的友元,那么在当前函数中就可以通过对象访问类的私有或者保护成员

注意:这个函数只能在外部定义,在当前类中引用即可

class A
{
public:
	A(int i=0):m_i(i){}
	int GetI()const
	{
		return m_i;
	}
	friend void Add(A& a, A& b);
protected:
	//friend void Add(A& a, A& b);//将Add函数作为类A的友元,在内部并不能定义
private:
	//friend void Add(A& a, A& b);//在保护和私有都能正确运行
	int m_i;
};

//想在Add函数中访问私有数据成员,又不想通过接口(共有函数)
void Add(A& a, A& b)
{
	cout << a.m_i << endl;
	cout << b.m_i << endl;
	cout << a.m_i + b.m_i << endl;
	//cout << a.GetI() + b.GetI() << endl;
}
void main()
{
	A a(5);
	A b(8);
	Add(a, b);
}

函数不止能作为一个类的友元

class B;//前向引用声明
class A
{
public:
	A(int i=0):m_i(i){}
	friend int Sum(A& a, B& b);//在这之前未定义class B,需进行声明
private:
	int m_i;
};
class B
{
public:
	B(int j = 0) :m_j(j) {}
	friend int Sum(A& a, B& b);//一般情况下放在共有里面
private:
	int m_j;
};
int Sum(A& a, B& b)
{
	return a.m_i + b.m_j;
}
void main()
{
	A a(20);
	B b(20);
	cout << Sum(a, b) << endl;
}

2、成员函数友元

一个类的成员函数作为另一个类的友元

注意:成员函数建议放在类外定义

class A;
class B
{
public:
	B(int j = 0) :m_j(j) {}
	void  Sub(A& a);
	void Print(A& a);
private:
	int m_j;
};
class A
{
public:
	A(int i = 0) :m_i(i) {}
	friend void B::Sub(A& a);//
	friend void B::Print(A& a);
private:
	int m_i;
};
void  B::Sub(A& a)
{
	cout << a.m_i - m_j << endl;
}
void B::Print(A& a)
{
	cout << a.m_i << endl;
}

void main()
{
	A a(40);
	B b(20);
	b.Sub(a);
}

3、类友元

一个类A作为另外一个类B的友元类,则A的所有的成员函数就可以访问B的私有数据成员或者保护

整个类可以是另一个类的友元。友元类的每个成员函数都是另一个类的友元函数,都可以访问另一个类中的所有成员,公有、保护或私有数据成员。 

class B;
class A
{
public:
	A(int a=0):m_a(a){}
	void print(B& b);
	void test(B& b);
	void show(B& b);
private:
	int m_a;
};
class B
{
public:
	B(int b=0):m_b(b)
    friend class A;
private:
	int m_b;
};
void A::print(B& b)
{
	cout <<"print"<< b.m_b << endl;
}
void A::test(B& b)
{
	cout << "test"<<b.m_b << endl;
}
void A::show(B& b)
{
	cout << "show"<<b.m_b << endl;
}
void main()
{
	B b(30);
	A a(40);
	a.print(b);
	a.show(b);
	a.test(b);
}

总结:

1、 友元函数不是类的成员函数,在函数体中访问对象的成员,必须用对象名加运算符"."加对象成员名。但友元函数可以访问类中的所有成员,一般函数只能访问类中的公有成员。

2、友元函数不受类中的访问权限关键字限制,可以把它放在类的公有、私有、保护部分,但结果都一样。

3、某类的友元函数的作用域并非该类作用域。如果该友元函数是另一类的成员函数,则其作用域为另一类的作用域,否则与一般函数相同。

二、友元特点:

1、友元是单向的:A是B的友元,并不意味B是A的友元

class B;
class A
{
public:
	A(int a=0):m_a(a){}
	void print(B& b);
	void test(B& b);
	void show(B& b);
	friend class B;
private:
	int m_a;
};
class B
{
public:
	B(int b=0):m_b(b){}
	friend class A;
	void Print(A& a);//
private:
	int m_b;
};
void B::Print(A& a)
{
	cout << a.m_a << endl;//友元是单向的,需在A中再次声明friend B
}
void A::print(B& b)
{
	cout <<"print"<< b.m_b << endl;
}
void A::test(B& b)
{
	cout << "test"<<b.m_b << endl;
}
void A::show(B& b)
{
	cout << "show"<<b.m_b << endl;
}
void main()
{
	B b(30);
	A a(40);
	a.print(b);
	a.show(b);
	a.test(b);
    b.Print(a);
}

2、友元是不能传递的:A是B的友元,B是C的友元,但A不是C的友元

 BB是AA的朋友,CC是BB的朋友,如果CC没有作为AA的友元类,则CC和AA没有关系——友元不能传递

class BB;
class CC;
class AA
{
public:
	AA(int a=0):m_a(a){}
	friend class BB;
private:
	int m_a;
};
class BB
{
public:

	friend class CC;
	void Show(AA& a);
private:
	int m_b;
};
class CC
{
public:
	void print(BB& b);
	void test(AA& a);
};
void BB::Show(AA& a)
{
	cout << a.m_a << endl;
}
void CC::print(BB& b)
{
	cout << b.m_b << endl;
}
void CC::test(AA& a)
{
	cout << a.m_a << endl;//error CC不是AA的朋友(友元不能传递)
}
void main()
{
}

3、友元是不能继承的:Base类型继承Object类型,如果Object类型是A的友元,但Base类型不是A友元。

三、友元函数在运算符重载中的应用

1、不同类型对象,但数据成员个数与类型一致,重载+

class B;
class A
{
public:
	A(int i=0):m_i(i){}
	int operator+(B& b);
private:
	int m_i;
};
class B
{
public:
	B(int j=0):m_j(j){}
	friend int A::operator+(B& b);
private:
	int m_j;
};
int A::operator+(B& b)
{
	return m_i + b.m_j;
}
void main()
{
	A a(10);
	B b(20);
	cout << a + b << endl;//a.+(b)  +(a,b)
}

2、 重载成员函数调用可以省略一个参数

重载友元函数不能省略

class A
{
public:
	A(int i=0):m_i(i){}
	void print()
	{
		cout << m_i << endl;
	}
	A operator+(A& b)//this
	{
		return m_i + b.m_i;
	}
	friend A operator-(A& a, A& b);
	A operator++(int)//a++值返回
	{
		int t = m_i;
		m_i = m_i + 1;
		return t;
	}
	friend A& operator++(A& a);
private:
	int m_i;
};
A operator-(A& a, A& b)
{
	return a.m_i - b.m_i;
}
A& operator++(A& a)
{
	++a.m_i;
	return a;
}
void main()
{
	A a(5);
	A b(10);
	(a + b).print();
	(a - b).print();
	(a++).print();
	(++b).print();
}

3、重载输出运算符(输出对象(即输出对象中的数据成员))

cout——ostream类的对象

cin——istream类的对象

cout<<a;

一般情况下运算符可以解析成下面两种形式:

1、cout.<<(a)  ostream类中重载了<<,程序员不能修改

2、<<(cout,a)  可以在程序员自己定义的类中将<<重载成友元

cout<<a<<b;

cout<<a这个表达式作为了上面的表达式<<左边,返回值为引用 (cout<<a)<<b

(cout<<a)<<b 表达式执行完后,还能继续用<<,说明返回值为ostream类型

friend ostream& operator<<(ostream &out,A &a)

class A
{
public:
	A(int i=0):m_i(i){}
    friend ostream& operator<<(ostream& out, A& a);
private:
	int m_i;
};
//cout<<a<<b  <<(cout,a)
ostream& operator<<(ostream& out, A& a)
{
	out << a.m_i;
	return out;
}
void main()
{
    A a(5);
    cout << a;//cout<<(a)   <<(cout,a)
}

练习: 

输出值为:0,8,5

class Magic
{
	double x;
public:
	Magic(double d=0.00):x(fabs(d)){}
	Magic operator+(Magic c)
	{
		return Magic(sqrt(x * x + c.x));
	}
	friend ostream& operator<<(ostream& os, Magic c);
	
};
ostream& operator<<(ostream& os, Magic c)
{
	return os << c.x;
}
void main()
{
	Magic ma;
	cout << ma << "," << Magic(-8) << "," << ma + Magic(-3) + Magic(-4);
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++友元函数 的相关文章

随机推荐

  • UML 绘图关系

    1 继承 子类继承父类 2 实现 实现类实现接口 3 依赖 偶然 临时 比较弱关联 类 A 使用了类 B 如果类 B 产生变化将会影响类A 4 关联 长期的 平等的 双向的 强依赖关系 强依赖关系 5 聚合关系 关联关系特例 体现的是 整体
  • spring-mvc 乱码问题的处理

    乱码问题的处理 当处理post请求时容易出现乱码 如果不是前端页面的问题的话 我们需要加入过滤器处理 大前提 tomcat要设置好 点开对应文件 conf server xml 找到connector
  • 基于simulink的16QAM仿真模型

    16QAM部分 具体的参数以及原模型的构架 我们做了调整请自行对比原来你提供的模型 这里 我们将给出所有的仿真图 串并 仿真结果如下所示 如图 这里输入的信号为1000001000 0110001010 0111101000 串并之后得到数
  • 神州交换机DHCPv6配置

    SWA配置 CS6200 28X EI gt ena CS6200 28X EI conf CS6200 28X EI config host SWA SWA config ipv6 enable SWA config service dh
  • 人脸识别研究

    转载自 https www jianshu com p 639e3f8b7253 本篇文章十分的长 大概有2万7千字左右 一 发展史 1 人脸识别的理解 人脸识别 Face Recognition 是一种依据人的面部特征 如统计或几何特征等
  • Docker与DevOps的无敌组合,引爆你的创新潜能

    荣誉认证 51CTO博客专家博主 TOP红人 明日之星 阿里云开发者社区专家博主 技术博主 星级博主 微信公众号 iOS开发上架 本文由iOS开发上架原创 欢迎关注 点赞 收藏 留言 首发时间 2023年8月7日 坚持和努力一定能换来诗与远
  • 如何批量修改照片后缀名

    有的时候我们写博客 或者干一些别的事情 需要大量的图片资源 于是我们会花费一些时间去zhaotup 把找到的图片都存在文件夹里面 但是 我们找到的图片所对应的格式可能不是我们所想要的格式 但是 我们可能下载了很多图片 不可能一个一个的去修改
  • 我个人认为.NET总有开源的一天

    我已经从事 Net平台的开源工作9年有余 最近跟朋友的聊天让我不禁回望 Net开源的这9年 记得2004年的 Net 1 1在当时是个热门 开源被认为是对微软的巨大威胁 Steve Balmer 也极力反对任何出现的开源 那时候对 NET平
  • elasticsearch常用命令操作集合

    文章目录 1 请求命令格式 2 关闭服务 3 添加员工信息 4 检索单个员工信息 5 检索所有员工信息 6 简单查询查询last name为Smith的员工信息 全匹配 7 DSL语句查询 查询last name为Smith的员工信息 全匹
  • thinkphp3错误:syntax error, unexpected 'list' (T_LIST), expecting identifier (T_STRING)

    syntax error unexpected list T LIST expecting identifier T STRING 出现这个错误的原因是 list是php的一个函数 系统冲突了 改成别的名字就可以了
  • java 操作excel (maven)

    资料地址 http www teamdev com downloads jexcel docs JExcel PGuide html 1 pom xml文件添加
  • 构造方法、类的初始化块以及类字段的初始化顺序

    构造方法 首先 以下代码为何无法通过编译 哪儿出错了 public class Test public static void main String args Foo obj1 new Foo class Foo int value pu
  • 如何写出高质量代码——站在巨人的肩膀上

    如何写出高质量代码 站在巨人的肩膀上 高质量代码的三要素 可读性 可维护性 可变更性 可读性强 可维护性 适应软件在部署和使用中的各种情况 1 3 可变更性 因需求变化而对代码进行修改 牛顿曾经说过 如果说我看得比别人更远 那是因为我站在巨
  • 遍历Newtonsoft.Json.Linq.JObject

    JObject 遍历 引用命名空间 using Newtonsoft Json Linq JObject jObject JObject Parse ID 001 Mark Hello Word StringBuilder str new
  • C++进阶:Makefile基础用法

    文章目录 1 Makefile基本语法与执行 2 Makefile简化过程 3 Makefile生成并使用库 3 1 动态库的建立与使用 3 2 动态加载库的建立与使用 1 Makefile基本语法与执行 作用 Makefile 文件告诉
  • 光纤收发器A,B端含义解释

    最近有朋友问到 光纤收发器型号或者收发器模块上A B字母的含义是什么 今天飞畅科技的小编就来为大家介绍一下 收发器中A B端字母的真正含义 一起来看看吧 首先 光纤收发器按光纤芯数分类有2种 一种是单模双纤光纤收发器 一种是单模单纤光纤收发
  • (二叉树)二叉树的序列化与反序列化

    题目描述 序列化是将一个数据结构或者对象转换为连续的比特位的操作 进而可以将转换后的数据存储在一个文件或者内存中 同时也可以通过网络传输到另一个计算机环境 采取相反方式重构得到原数据 请设计一个算法来实现二叉树的序列化与反序列化 这里不限定
  • Highway network

    Highway Network主要解决的问题是 网络深度加深 梯度信息回流受阻造成网络训练困难的问题 假设定义一个非线性变换为 定义门函数 携带函数 对于门函数取极端的情况0 1会有 而对应的门函数使用sigmoid函数 则极端的情况不会出
  • Java接口详解

    一 static静态关键字 定义变量不加static关键字 每个对象单独保存一个变量 定义变量加static关键字 静态变量 类变量 共享变量 public static 数据类型 变量名 所有对象会共享该变量 如果一个变量 静态变量 类变
  • C++友元函数

    友元 让函数或者类作为另外一个类的朋友 则可以访问当前类的private或者protected 友元friend机制允许一个类授权其他的函数访问它的非公有成员 友元声明以关键字friend开头 它只能出现在类的声明中 它们不受其在类体中的p