前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >类A的成员函数做类B的友元函数

类A的成员函数做类B的友元函数

作者头像
我与梦想有个约会
发布2023-10-20 16:36:59
1370
发布2023-10-20 16:36:59
举报
文章被收录于专栏:jiajia_dengjiajia_deng

这种方法相对麻烦,主要是在两个类之间的前后声明有着复杂的逻辑关系。但只要我们理清思路,是可以实现的。跟着我从最初的想法到实现一步一步的理顺逻辑,就非常容易理解如何操作了。

首先,我们要实现让 ManagerPoint 类中的成员函数 distance() 操作 Point 类中的私有数据成员_x和_y,所以要将 ManagerPoint 类中的 distance() 函数在 Point 类中声明为友元函数。如下代码:

代码语言:javascript
复制
#include
 
using namespace std;
 
class Point
{
public:
Point(int xx, int yy)
{
_x = xx;
_y = yy;
}
 
void display()
{
cout << “(“ << _x << “,” << _y << “)” << endl;
}
 
// 将 ManagerPoint 中的 distance 函数声明为友元函数
// 找不到 ManagerPoint 类!
friend ManagerPoint::distance(Point& a, Point& b);
 
private:
int _x;
int _y;
};
 
class ManagerPoint
{
public:
// 尝试访问 Point 类中的私有成员 失败!
int distance(Point& a, Point& b)
{
int dx = a._x - b._x;
int dy = a._y - b._y;
return sqrt(dx * dx + dy * dy);
}
};
 
int main(int argc, char* argv[])
{
Point p1(3, 4), p2(6, 8);
p1.display();
p2.display();
ManagerPoint mp;
int d = mp.distance(p1,p2);
cout << “Distance is : “ << d << endl;
 
getchar();
return 0;

}

但这样的代码编译时你会发现,Point 类因为找不到 ManagerPoint 类的声明,编译时会报错,提示ManagerPoint 不是类或命名空间:

2015-05-15_220416
2015-05-15_220416

因为 ManagerPoint 类是在 Point 类之后声明定义的,所以他找不到,这样我们需要将 ManagerPoint 类的声明和定义移动到 Point 类之前。移动后的代码如下:

代码语言:javascript
复制
#include
 
using namespace std;
 
class ManagerPoint
{
public:
// 无法识别 Point 是一个什么类型,因为这段代码前并没有声明或定义 !
int distance(Point& a, Point& b)
{
int dx = a._x - b._x;
int dy = a._y - b._y;
return sqrt(dx * dx + dy * dy);
}
};
 
class Point
{
public:
Point(int xx, int yy)
{
_x = xx;
_y = yy;
}
 
void display()
{
cout << “(“ << _x << “,” << _y << “)” << endl;
}
 
// 将 ManagerPoint 中的 distance 函数声明为友元函数
friend ManagerPoint::distance(Point& a, Point& b);
 
private:
int _x;
int _y;
};
 
int main(int argc, char* argv[])
{
Point p1(3, 4), p2(6, 8);
p1.display();
p2.display();
ManagerPoint mp;
int d = mp.distance(p1,p2);
cout << “Distance is : “ << d << endl;
 
getchar();
return 0;
}

但这样编译又会报错,因为你在 ManagerPoint 类中使用了Point类,很明显,在ManagerPoint之前并没有声明或定义Point类,那么我们可以使用一种手段叫做“前向声明”的方式,将 Point 类声明在 ManagerPoint 类之前。(前向型声明又称为不完全型声明,只能骗过引用或指针,因为引用或指针都是固定大小的,只要在需要的位置给其留下固定大小的空间即可,但如果 ManagerPoint 类中的 distance() 函数是值传递的 Point 的对象,就必须要计算出 Point 类所占用空间的大小,因为只做了简单的前向声明,不清楚 Point 类中都有什么成员,是无法计算出 Point 类的大小的,所以前向声明是骗不过值传递的)代码如下:

代码语言:javascript
复制
#include
 
using namespace std;
 
// 前向声明 Point 类
class Point;
 
class ManagerPoint
{
public:
// 尝试访问 Point 类中的私有成员 失败!
int distance(Point& a, Point& b)
{
int dx = a._x - b._x;
int dy = a._y - b._y;
return sqrt(dx * dx + dy * dy);
}
};
 
class Point
{
public:
Point(int xx, int yy)
{
_x = xx;
_y = yy;
}
 
void display()
{
cout << “(“ << _x << “,” << _y << “)” << endl;
}
 
// 将 ManagerPoint 中的 distance 函数声明为友元函数
friend ManagerPoint::distance(Point& a, Point& b);
 
private:
int _x;
int _y;
};
 
int main(int argc, char* argv[])
{
Point p1(3, 4), p2(6, 8);
p1.display();
p2.display();
ManagerPoint mp;
int d = mp.distance(p1,p2);
cout << “Distance is : “ << d << endl;
 
getchar();
return 0;
}

这样是不是就万事大吉了?? 不,还没那么简单,这样编译后,又出现了新问题,如下图:

2015-05-15_220537
2015-05-15_220537

编译器提示,Point是一个未定义的类,因为我们直接操作了Point类中的_x和_y成员,而我们之前只给出了Point类的一个前向声明,并没有告诉它Point类中都有什么成员。所以这里操作时依然是行不通的。那难道就这样罢手了吗? 换位思考一下,当我们将前 Point 类做了前向声明后,ManagerPoint类中的 distance() 函数已经可以识别 Point 这个类型了,也就是说,如果我们这里只做 distance() 函数的声明,而把distance() 函数的实现放到 Point 类的后面,是不是就可以避免以上所有遇到的问题了呢?

代码语言:javascript
复制
#include
 
using namespace std;
 
// 前向声明 Point 类
class Point;
 
class ManagerPoint
{
public:
// 只做声明,这里已经可以通过前向声明的Point识别Point类型
int distance(Point& a, Point& b);
};
 
class Point
{
public:
Point(int xx, int yy)
{
_x = xx;
_y = yy;
}
 
void display()
{
cout << “(“ << _x << “,” << _y << “)” << endl;
}
 
// 将 ManagerPoint 中的 distance 函数声明为友元函数
friend ManagerPoint::distance(Point& a, Point& b);
 
private:
int _x;
int _y;
};
 
// 声明在前,定义在后,将distance方法在Point类后面定义
// 不但解决了找不到Point类型的问题,而且还知道了Point类中都具有什么成员
int ManagerPoint::distance(Point& a, Point& b)
{
int dx = a._x - b._x;
int dy = a._y - b._y;
return sqrt(dx * dx + dy * dy);
}
 
int main(int argc, char* argv[])
{
Point p1(3, 4), p2(6, 8);
p1.display();
p2.display();
ManagerPoint mp;
int d = mp.distance(p1,p2);
cout << “Distance is : “ << d << endl;
 
getchar();
return 0;
}

不错,以上代码可以顺利编译通过,我们成功的解决了两个类之间,某一个类的成员函数作为另外一个类的友元函数的实现。 对比一下最初的代码,我们做了3处的改动,如下图:

2015-05-15_222583
2015-05-15_222583
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2015-05-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档