友元

时间:2022-07-24
本文章向大家介绍友元,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。

友元函数

声明友元函数

友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。 格式如下:

class Myclass
{
	public:
		……
		friend void add(int n );
	……
}

友元函数的特点:

友元函数可以使一个普通的函数,也可以是其他类的函数,但它一定不是本类的成员函数。 一般成员函数只可以访问一个类的私有和保护的成员,但友元函数可以访问多个类的私有和保护函数。 友元函数可以绕过成员函数,直接访问类的私有和保护函数,这样就避免了调用成员函数相关的开销。 如果没有友元功能,一个函数要想访问某个类的私有和保护的成员时,只能是将这个成员设置为公共的,这样一来用户就可以访问该类中的所有成员,从而破坏了信息的隐蔽性。 由于友元函数不是本类的成员函数。其定义和调用方式与普通函数一样,在调用友元函数时不需要使用“ · ”运算符,在定义时不需要实用类前缀。 友元函数并不是类的成员函数,他不带有this指针。所以必须用对象名或对象的引用作为友元函数的形参,并在函数体内使用运算符“.”来访问对象的成员。 由于友元函数可使用类里面的所有成员,从而破坏数据的安全性,所以使用友元函数必须谨慎,不要通过友元函数对数据成员进行危险的操作。

例:

//编写一个函数,以友元函数的方式计算一个点到一条直线的距离
#include<iostream>
#include<math.h>
using namespace std;
class Point
{
public:
	Point(int x1, int y1){ x = x1; y = y1; }
	int x, y;
};
class Line//线类
{
	int a, b, c;
public:
	Line(int a1, int b1, int c1){ a = a1; b = b1; c = c1; }
	friend double dist(Line l, Point p)
	{
		double d;
		d = abs(l.a*p.x + l.b*p.y + l.c) / (sqrt(l.a*l.a + l.b*l.b));
		return d;
	}
};
void main()
{
	Point p(10, 10);
	Line l(2, 4, -3);
	cout << "d=" << dist(l, p) << endl;
	system("pause");
}

友元类

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。

友元关系是单向的,不具有交换性。比如上述Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。 友元关系不能传递 如果B是A的友元,C是B的友元,则不能说明C时A的友元。

例:编写一个程序,实现栈的压入和弹出。其中有两个类:一个是结点类Node,它包含结点值data和指向下一个节点next,另一个类是栈Stack,它包含头指针top。

#include<iostream>
using namespace std;
class Stack;
class Node
{
	int data;
	Node *next;
public:
	Node(int d)
	{
		data = d;
		next = NULL;
	}
	friend class Stack;
};

class Stack
{
	Node *top;
public:
	Stack()
	{
		top = NULL;
	}
	void push(int d)
	{
		Node *p = new Node(d);
		if (top != NULL)
			p->next = top;
			top = p;
	}
	int pop(int &c)
	{
		Node *p = top;
		if (top != NULL)
		{
			c = p->data;
			top = top->next;
			delete p;
			return 1;
		}
		else return 0;
	}
};

void main()
{
	Stack s;
	int c;
	s.push(1);
	s.push(2);
	s.push(3);
	s.push(4);
	cout << "出栈次序:";
	while (s.pop(c))
		cout << c << " ";
	cout << endl;
	system("pause");
}