C++友元

11 篇文章 0 订阅

前言

采用类的机制后实现了数据的隐藏与封装,类的数据成员一般定义为私有成员,成员函数一般定义为公有的,依此提供类与外界间的通信接口。但是,有时需要定义一些函数,这些函数不是类的一部分,但又需要频繁地访问类的数据成员,这时可以将这些函数定义为该函数的友元函数。除了友元函数外,还有友元类,两者统称为友元。友元的作用是提高了程序的运行效率(即减少了类型检查和安全性检查等都需要时间开销),但它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。

1.友元函数

1.1全局有元函数

例子

#include <iostream>
#include <string>

using namespace std;
class Person
{
	friend void setage(Person& p2,int age);
public:
	Person()
	{
		age = 10;
		length = 20;
	}
private:
	int age;
	int length;

};
void setage(Person &p2,int age)
{
	printf("%d", p2.age=age);
}
int main()
{
	Person p1;
	setage(p1,20);


	system("pause");
	return 0;
}

解释

首先全局友元函数是全局函数,也就是我们经常见到的普通函数,就是上图中的setage函数。而要想让全局函数变为友元函数,只需要在类的定义中添加声明即可。声明的方式为:

  • friend 类型名 函数名 形参列表
    在这个例子中,就是
  • friend void setage (Person &p2,int age);

总结:想要定义一个全局友元函数,先定义一个全局函数(普通函数),再在类的定义中添加该函数的声明即可。
全局友元函数并不能看做是类的成员函数,它只是个被声明为友元的普通函数

1.2.成员有元函数

例子

#include <iostream>
#include <string>

using namespace std;
class Person;
class animal
{

public:
	void setage(Person& p2, int age);
};

class Person
{
	friend void animal::setage(Person& p2, int age);
public:
	Person()
	{
		age = 10;
		length = 20;
	}
private:
	int age;
	int length;

};
void animal::setage(Person& p2, int age)
{
	printf("%d",p2.age = age);
}


int main()
{
	Person p1;
	animal a1;
	a1.setage(p1,35);
    

	system("pause");
	return 0;
}

解释

首先成员友元函数是成员函数,它的声明或定义在某一个类中,就是上图中的
animal::setage 函数,而要想将成员函数变为友元函数,在类中添加声明即可。

  • friend 类型名 类名::函数名 形参列表
    在这个例子中,就是
  • friend void animal::setage (Person &p2,int age);

总结:想要定义一个成员友元函数,先定义一个友元函数,再在类的定义中添加该函数的声明即可。

2.友元类

例子

#include <iostream>
#include <string>

using namespace std;
class Person;
class animal
{

public:
	void setage(Person& p2, int age);
};

class Person
{
	friend class animal;
public:
	Person()
	{
		age = 10;
		length = 20;
	}
private:
	int age;
	int length;

};
void animal::setage(Person& p2, int age)
{
	printf("%d",p2.age = age);
}


int main()
{
	Person p1;
	animal a1;
	a1.setage(p1,35);
    

	system("pause");
	return 0;
}

解释

首先友元类是一个类,就是上图中的class animal 。要想将类变为友元类,在类中声明即可。

  • friend class 类名
    在这个例子中,就是
  • friend class animal;

总结:想要定义一个友元类,先定义一个类,再在类的定义中添加该类的声明即可。

3.友元的细节与注意事项

细节

  • 友元函数或类的声明可以放在类的私有部分,也可以放在公有部分,它们是没有区别的,都说明是该类的一个友元函数或类。
  • 一个函数或类可以是多个类的友元函数或类,只需要在各个类中分别声明
  • 友元函数的调用与一般函数的调用方式和原理一致。
  • 友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。

注意事项

  • 友元关系不能被继承。
  • 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。
  • 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明

小节:类A到底是不是类B的友元,取决于A类是否在B类的定义中声明了。

4.友元的优缺点

如果将类的封装比喻成一堵墙的话,那么友元机制就像墙上了开了一个门,那些得 到允许的类或函数允许通过这个门访问一般的类或者函数无法访问的私有属性和方法。友元机制使类的封装性得到消弱,所以使用时一定要慎重。
  只有你赋予某个类为你的友元时,那个类才有访问你的私有数据的权利。
  通常对于普通函数来说,要访问类的保护成员是不可能的,如果想这么做那么必须把类的成员都生命成为public(共用的),然而这做带来的问题遍是任何外部函数都可以毫无约束的访问它操作它,c++利用friend修饰符,可以让一些你设定的函数能够对这些保护数据进行操作,避免把类成员全部设置成public,最大限度的保护数据成员的安全。
友元能够使得普通函数直接访问类的保护数据,避免了类成员函数的频繁调用,可以节约处理器开销,提高程序的效率。
但所矛盾的是,即使是最大限度大保护,同样也破坏了类的封装特性,这即是友元的缺点,在现在cpu速度越来越快的今天我们并不推荐使用它。

小节:我们不推荐使用友元,目的是使类的封装这堵墙没有任何们可以通过。

友元的使用方式

现在我们已经会友元的声明了,但是我们如何去使用友元呢?
以下图例子为例

#include <iostream>
#include <string>

using namespace std;
class Person;
class animal
{

public:
	void setage(Person& p2, int age);
};

class Person
{
	friend class animal;
public:
	Person()
	{
		age = 10;
		length = 20;
	}
private:
	int age;
	int length;

};
void animal::setage(Person& p2, int age)
{
	printf("%d",p2.age = age);
}


int main()
{
	Person p1;
	animal a1;
	a1.setage(p1,35);
    

	system("pause");
	return 0;
}

步骤:
1.先定义一个对象(对象的实例化)
2.调用友元函数

注意:友元函数的形参是特殊的,形参列表中一定要有能够存储对象地址的变量或是与对象类型相同的引用。
调用友元函数对对象的私有属性进行访问,本质就是对象调用对象的私有属性。
因为正常情况下对象是不可以掉用对象的私有属性的。

总结

文章讲述了C++中友元的定义,注意事项,优缺点等等特点。
但我的建议是能别用友元就别用友元,因为它破坏了类的封装特性,带来了很多不好的结果。
调用友元函数对对象的私有属性进行访问,本质就是对象调用对象的私有属性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值