返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >一篇文章详细解释C++的友元(friend)
  • 308
分享到

一篇文章详细解释C++的友元(friend)

2024-04-02 19:04:59 308人浏览 薄情痞子
摘要

目录一.友元函数先看普通函数声明为友元函数:再看类成员函数声明为友元函数:最后说明二.友元类三.完整示例:四.同一个类(class)的类对象(object)互为友元总结一.友元函数

一.友元函数

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

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

如下所示:

#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的私有数据成员。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注编程网的更多内容!

--结束END--

本文标题: 一篇文章详细解释C++的友元(friend)

本文链接: https://lsjlt.com/news/141727.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 一篇文章详细解释C++的友元(friend)
    目录一.友元函数先看普通函数声明为友元函数:再看类成员函数声明为友元函数:最后说明二.友元类三.完整示例:四.同一个类(class)的类对象(object)互为友元总结一.友元函数 ...
    99+
    2024-04-02
  • C++超详细讲解友元的使用
    目录一、友元的概念二、友元的用法三、友元的语法四、友元的尴尬五、注意事项六、小结一、友元的概念 什么是友元友元是 C++ 中的一种关系友元关系发生在函数与类之间或者类与类之间友元关系...
    99+
    2024-04-02
  • 一篇文章带你详细了解JavaScript数组
    目录一、数组的作用:二、数组的定义:1.通过构造函数创建数组2.通过字面量的方式创建数组三、数组元素四、数组长度五、数组索引(下标)六、数组注意的问题1.数组中存储的数据可以是不一样...
    99+
    2024-04-02
  • 一篇超详细的SpringBoot整合MybatisPlus的文章
    目录创建个SpringBoot项目写个HelloController测试下使用代码生成器生成代码添加所需的依赖CodeGenerator运行代码生成器,在控制台输入想要生成的表总结创...
    99+
    2024-04-02
  • 一篇超详细的Spring Boot整合Mybatis文章
    目录配置文件形式pom.xmlapplication.yml:UserMapper.xmlUserMapper配置springboot整合mybatis在运行类上添加@MapperS...
    99+
    2024-04-02
  • 一篇文章超详细的介绍Java继承
    目录前言继承继承的优点重写和隐藏父类方法重写父类中的方法隐藏父类中的方法方法重写和隐藏后的修饰符子类访问父类私有成员使用super关键字使用super调用父类的无参数构造方法/有参数...
    99+
    2024-04-02
  • 一篇文章带你详细了解python中一些好用的库
    目录时间库—arrow使用背景安装arrowarrow使用游标卡尺shift获取arrow对象arrow的类型转换和时区修改总结时间库—arrow 使用背景 日期时间处理在实际应用场...
    99+
    2024-04-02
  • 一篇文章带你详解Spring的AOP
    目录1、AOP 什么?2、需求3、解决办法1:使用静态代理第一步:创建 UserService 接口第二步:创建 UserService的实现类第三步:创建事务类 MyTransac...
    99+
    2024-04-02
  • C++超详细讲解友元与内部类
    目录一.友元1.友元函数(1)引入原因(2)友元函数作用(3)友元函数特征2.友元类(1)解释(2)友元类特征二.内部类(不常用)1.概念2.特性 一.友元 友元分为: 友...
    99+
    2024-04-02
  • 一篇文章带你了解C++智能指针详解
    目录为什么要有智能指针?智能指针的使用及原理RALLshared_ptr的使用注意事项创建多个 shared_ptr 不能拥有同一个对象shared_ptr 的销毁shared_pt...
    99+
    2024-04-02
  • 一篇文章带你了解C++模板编程详解
    目录模板初阶泛型编程函数模板函数模板概念函数模板格式函数模板的原理函数模板的实例化模板参数的匹配原则类模板类模板的定义格式类模板的实例化总结模板初阶 泛型编程 在计算机程序设计领域...
    99+
    2024-04-02
  • 一篇超详细的Spring Boot对jdbc支持的文章
    目录项目结构pom.xml启动类Dao层Service层Controller层测试类测试总结项目结构 pom.xml pom.xml: <?xml version...
    99+
    2024-04-02
  • 一篇文章了解c++中的new和delete
    目录new expressiondelete expressionnew[]和new()new[]和delete[]new的内存分布placement newnew失败处理捕捉异常禁...
    99+
    2024-04-02
  • Java读取excel的方式,一篇文章看懂(详细)
    目录 一、excel读取的两种方式 1.1 jxl 和 poi 的区别和选择 二、jxl 的使用 2.1 导入相关依赖  2.2 操作 三、poi 的使用 3.1 导入相关依赖 3.2 操作 四、总结 一、excel读取的两种方式 J...
    99+
    2023-09-03
    java jar intellij-idea spring
  • 一篇文章带你详解Spring的概述
    目录1、什么是 Spring 2、Spring 起源3、Spring 特点①、方便解耦,简化开发②、AOP编程的支持③、声明式事务的支持④、方便程序的测试⑤、方便集成各种优秀框架⑥、...
    99+
    2024-04-02
  • 一篇文章带你了解python元组基础
    目录1. 元组基本知识1.元组的基本格式和用法2. 元组操作实例1.建立元组2.查找元素:通过元组下标实现。3.删除元组:对元组的删除时不允许的,可以通过del函数,实现对整个元组对...
    99+
    2024-04-02
  • 一篇文章带你了解C++的KMP算法
    目录KMP算法步骤1:先计算子串中的前后缀数组NextC++代码:步骤2:查找子串在母串中出现的位置。总结KMP算法 KMP算法作用:字符串匹配 例如母串S = “aaagoogle...
    99+
    2024-04-02
  • 一篇文章带你了解C++中的异常
    目录异常抛出异常基本操作自定义的异常类栈解旋异常接口声明异常变量的生命周期异常的多态c++的标准异常库编写自己的异常类总结异常 在c语言中,对错误的处理总是两种方法: 1,使用整型的...
    99+
    2024-04-02
  • 一篇文章带你了解C/C++的回调函数
    目录函数指针概念先来看一个Hello World程序然后,采用函数调用的形式来实现用函数指针的方式来实现函数指针数组回调函数概念标准Hello World程序将它修改成函数回调样式修...
    99+
    2024-04-02
  • 一篇文章带你详细理解java中类的继承与多态
    类的继承子类及其定义子类的定义使用关键字extends格式:class SubClass extends SuperClass{ ........ }子类可以继承父类的属性和方法;子类不能继承带private修饰符的属性,方法;子类不能继承...
    99+
    2017-08-28
    java入门 java 继承 多态
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作