IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++友元(friend)解释 -> 正文阅读

[C++知识库]C++友元(friend)解释


友元是什么,说白了一句话,就是为了不受类的封装性的约束 ,好让我们可以 访问类私有数据成员。语法上使用friend关键字。

一.友元函数

友元函数可以是普通函数或者类成员函数。

先看普通函数声明为友元函数:

如下所示:

#include <iostream>
#include <cmath>

using namespace std;

class Point
{
    //普通函数声明为类的友元函数
	friend double TwoPointsDistant(const Point& pnt1, const Point& pnt2);
public:
	Point(double x=0, double y=0)
		:_x(x), _y(y)
	{}
	double getPointXAxis() const { return this->_x; }
	double getPointYAxis() const { return this->_y; }
private:
	double _x;
	double _y;
};


//计算两点的距离
double TwoPointsDistant(const Point& pnt1, const Point& pnt2)
{
	return sqrt(  pow((pnt1._x - pnt2._x), 2) + pow((pnt1._y - pnt2._y), 2)   );
}

int main()
{
	Point point1(1.1,2.2);
	Point point2(3.3, 4.4);

	cout << TwoPointsDistant(point1, point2) << endl;
	
	system("pause");
	return 0;
}

这里说明一点:TwoPointsDistant()函数必须在Point类的定义下面,至于原因,很简单,你若放在Point上面,Point的数据成员_x和_y都没定义呢,你用个锤子。

再看类成员函数声明为友元函数:

还以上面的类为例,现在加一个_PointMove_类,它有一个成员函数_PointAxisAddOne,_作用是将点的坐标都加1。如下:

class PointMove
{
public:
	void PointAxisAddOne(Point& pnt);
};

这里就出现了一个问题:_Point_和_PointMove_哪个放在前面?先给出答案,应该把_PointMove_放在前面,并且是必须的,如下:

class Point;//前向声明Point

class PointMove
{
public:
	void PointAxisAddOne(Point& pnt);
};

class Point
{
    //普通函数声明为类的友元函数
	friend double TwoPointsDistant(const Point& pnt1, const Point& pnt2);
    //类成员函数声明为友元
	friend void PointMove::PointAxisAddOne(Point& pnt);
    /*这里同前*/
};

//类成员函数的定义
void PointMove::PointAxisAddOne(Point& pnt)
{
	pnt._x = pnt._x + 1;
	pnt._y = pnt._y + 1;
}

这里注意,对于类的成员函数,声明为其他类的友元函数时需要加上类的作用域,即指出该函数属于哪个类。如上面的_PointMove::_。
?

同时,需要说明的是,PointAxisAddOne()函数的定义是必须放在Point类定义后面的,这和普通函数的道理是一样的。

最后说明

  1. 一个函数Func被声明为类A的友元函数,那么是不能直接使用this指针来访问类A的数据成员的(当然,若Func是类B的成员函数,它可以通过this访问类B的数据成员),这和成员函数不同。
  2. 一个函数Func为什么要声明为某个类A的友元,就是因为函数的参数类型为类A类型,我想访问这个类对象的数据成员,所以被声明为类A的友元函数的参数类型必定为类A,如friend Func(A& obj);

二.友元类

若是将一个类C都声明为另一个类A的友元类,则类C中的成员函数均可访问类A中的私有数据成员。如下:

class Point
{
    //友元类
    friend class PointInfo;
    ...
}
class PointInfo
{
public:
	//打印点所处象限
	void PrintQuadrant(const Point& pnt) const
	{
		if (pnt._x > 0 && pnt._y > 0)
			cout << "点"<<"(" << pnt._x << "," << pnt._y<<")" <<"处于第一象限" << endl;
	}
};

当然,你也可以把_PointInfo_写在_Point_前,只是函数_PrintQuadrant()_的定义就不能在类内实现了,只能在_Point_后实现,原因和前面一样,不再赘述。

三.完整示例:

#include <iostream>
#include <cmath>

using namespace std;

class Point;

class PointMove
{
public:
	void PointAxisAddOne(Point& pnt);
};


class PointInfo
{
public:
	//打印点所处象限
	void PrintQuadrant(const Point& pnt) const;
};

class Point
{
	friend class PointInfo;

	friend double TwoPointsDistant(const Point& pnt1, const Point& pnt2);
	friend void PointMove::PointAxisAddOne(Point& pnt);

public:
	Point(double x=0, double y=0)
		:_x(x), _y(y)
	{}
	double getPointXAxis() const { return this->_x; }
	double getPointYAxis() const { return this->_y; }

	void PrintAxis(const Point& pnt) const
	{
			
	}
private:
	double _x;
	double _y;
};

//打印点所处象限
void PointInfo::PrintQuadrant(const Point& pnt) const
{
	if (pnt._x > 0 && pnt._y > 0)
	cout << "点"<<"(" << pnt._x << "," << pnt._y<<")" <<"处于第一象限" << endl;
}

void PointMove::PointAxisAddOne(Point& pnt)
{
	pnt._x = pnt._x + 1;
	pnt._y = pnt._y + 1;
}


double TwoPointsDistant(const Point& pnt1, const Point& pnt2)
{
	return sqrt(  pow((pnt1._x - pnt2._x), 2) + pow((pnt1._y - pnt2._y), 2)   );
}

int main()
{
	Point point1(1.1,2.2);
	Point point2(3.3, 4.4);

	cout << TwoPointsDistant(point1, point2) << endl;

	PointInfo pf;
	pf.PrintQuadrant(point1);

	system("pause");
	return 0;
}

VS2015打印结果:
打印结果

四.同一个类(class)的类对象(object)互为友元

还以上面给出的例子为基础,现在在_Point_类加一个成员函数func(const Point& pnt),它返回点的x轴和y轴的和。如下所示。

class Point
{
    /*这里同上*/
	double func(const Point& pnt)
	{
		return pnt._x + pnt._y;
	}
private:
	double _x;
	double _y;
};

现在我生成两个对象,并作如下操作:

	Point point1(1.1,2.2);
	Point point2(3.3, 4.4);

	cout << point1.func(point2) << endl;

最后的结果是打印出7.7。看到这里不知道你有没有疑问:为什么可以通过point1直接访问point2的私有数据成员,而没有将func()声明为友元函数?侯捷老师是这么解释的:相同class的各个objects之间互为友元。
所以对于一个类A,若有一个成员函数Fun(A& arg),可以通过arg直接访问A的私有数据成员。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-08 22:10:02  更:2022-03-08 22:10:37 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 5:01:15-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码