服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - 一篇文章详细解释C++的友元(friend)

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

2022-10-13 14:33代码乌龟 C/C++

这篇文章主要为大家详细介绍了C++的友元(friend),文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

一.友元函数

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

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

如下所示:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#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 sqrtpow((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。如下:

?
1
2
3
4
5
class PointMove
{
public:
    void PointAxisAddOne(Point& pnt);
};

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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中的私有数据成员。如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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_后实现,原因和前面一样,不再赘述。

三.完整示例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#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 sqrtpow((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打印结果:

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

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

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

?
1
2
3
4
5
6
7
8
9
10
11
class Point
{
    /*这里同上*/
    double func(const Point& pnt)
    {
        return pnt._x + pnt._y;
    }
private:
    double _x;
    double _y;
};

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

?
1
2
3
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的私有数据成员。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注服务器之家的更多内容!

原文链接:https://blog.csdn.net/weixin_43744293/article/details/123327548

延伸 · 阅读

精彩推荐
  • C/C++OpenCV利用背景建模检测运动物体

    OpenCV利用背景建模检测运动物体

    这篇文章主要为大家详细介绍了OpenCV利用背景建模检测运动物体,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    yangchuankai4222021-06-15
  • C/C++C语言模拟实现密码输入的示例代码

    C语言模拟实现密码输入的示例代码

    本文主要介绍了C语言模拟实现密码输入的示例代码,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    小倪同学 -_-7272022-09-29
  • C/C++C语言自增(++)和自减(--)实例详解

    C语言自增(++)和自减(--)实例详解

    本篇文章主要介绍了C语言的自增和自减的基本知识,并附有代码示例,以便大家理解,有需要的朋友可以看下...

    C语言教程网9452021-04-09
  • C/C++C++ COM编程之接口背后的虚函数表

    C++ COM编程之接口背后的虚函数表

    这篇文章主要介绍了C++ COM编程之接口背后的虚函数表,COM的背后,就是接口,而接口的背后,就是虚函数表,需要的朋友可以参考下...

    果冻想5882021-02-04
  • C/C++老生常谈C语言动态函数库的制作和使用(推荐)

    老生常谈C语言动态函数库的制作和使用(推荐)

    下面小编就为大家带来一篇老生常谈C语言动态函数库的制作和使用(推荐)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来...

    C语言教程网4152021-04-15
  • C/C++解读C++编程中派生类的构成和创建

    解读C++编程中派生类的构成和创建

    这篇文章主要介绍了解读C++编程中派生类的构成和创建,是C++入门学习中的基础知识,需要的朋友可以参考下...

    C++教程网7192021-03-14
  • C/C++c++基础语法:普通继承

    c++基础语法:普通继承

    基类成员的private成员不但对于对象是不可见的,对于派生类也是不可见的,只能被基类成员或者友元访问...

    C++教程网8402021-01-01
  • C/C++C++数组和指针的区别与联系

    C++数组和指针的区别与联系

    这篇文章主要介绍了C++数组和指针的区别与联系,数组是具有固定大小和连续内存空间的相同数据集合,指针是指存放内存地址的变量,更多详细资料请参考...

    龙小5772022-08-10