C++友元函数和友元类
类中的成员通过权限控制符实现了数据的封装,若对象要访问类中的私有数据,则只能通过成员函数实现。
这种方式实现了数据的封装却增加了开销,有时候需要通过外部函数或类直接访问其他类的私有成员,为此 C++ 提供了友元,使用友元可以访问类中的所有成员,函数和类都可以作为友元。
接下来分别讲解类外定义的普通函数作为类的友元函数和类成员函数作为友元函数的用法。
普通函数作为类的友元函数的声明格式如下所示:
【示例1】通过案例演示普通函数作为友元函数的用法,C++ 代码如下:
从运行结果 可以看出,普通函数作为友元函数访问了类中的私有成员,且具有修改私有成员的权限。
【示例2】通过案例演示类的成员函数作为其他类的友元函数的用法,C++ 代码如下:
与声明友元函数类似,友元类也是使用关键字
【示例3】通过案例演示友元类的用法,C++ 代码如下:
使用友元需要注意以下几点:
声明:《C++系列教程》为本站“54笨鸟”官方原创,由国家机构和地方版权局所签发的权威证书所保护。
这种方式实现了数据的封装却增加了开销,有时候需要通过外部函数或类直接访问其他类的私有成员,为此 C++ 提供了友元,使用友元可以访问类中的所有成员,函数和类都可以作为友元。
C++友元函数
友元函数可以是类外定义的函数或者是其他类中的成员函数,若在类中声明某一函数为友元函数,则该函数可以操作类中的所有数据。接下来分别讲解类外定义的普通函数作为类的友元函数和类成员函数作为友元函数的用法。
1) 普通函数作为友元函数
将普通函数作为类的友元函数,在类中使用friend 关键字声明该普通函数就可以实现,友元函数可以在类中任意位置声明。普通函数作为类的友元函数的声明格式如下所示:
class 类名
{
friend 函数返回值类型 友元函数名(形参列表);
... //其他成员
}
【示例1】通过案例演示普通函数作为友元函数的用法,C++ 代码如下:
#include<iostream>
using namespace std;
class Circle
{
friend void getArea(Circle &circle); //声明普通函数getArea()为友元函数
private:
float _radius;
const float PI=3.14;
public:
Circle(float radius);
~Circle();
};
Circle::Circle(float radius=0):_radius(radius)
{
cout<<"初始化圆的半径为:"<<_radius<<endl;
}
Circle::~Circle(){}
void getArea(Circle &circle)
{
//访问类中的成员变量
cout<<"圆的半径是:"<<circle._radius<<endl;
cout<<"圆的面积是"<<circle.PI*circle._radius*circle._radius<<endl;
cout<<"友元函数修改半径:"<<endl;
circle._radius=1;
cout<<"圆的半径是:"<<circle._radius<<endl;
}
int main()
{
Circle circle(10);
getArea(circle);
return 0;
}
运行结果:
初始化圆的半径为:10
圆的半径是:10
圆的面积是314
友元函数修改半径:
圆的半径是:1
- 第 3~12 行代码定义了关于圆的类 Circle,其中圆的半径 _radius 和圆周率 PI 是私有成员;
- 第 5 行代码在类中声明了友元函数 getArea(),用于计算圆的面积;
- 第 18~26 行代码是 getArea() 函数的实现;
- 第 29 行代码创建对象 circle,并初始化圆的半径为 10;
- 第 30 行代码调用友元函数 getArea() 计算圆的面积,面积计算完成后,修改圆的半径为 1。
从运行结果 可以看出,普通函数作为友元函数访问了类中的私有成员,且具有修改私有成员的权限。
2) 其他类的成员函数作为友元函数
其他类中的成员函数作为本类的友元函数时,需要在本类中表明该函数的作用域,并添加友元函数所在类的前向声明,其语法格式如下:
class B; //声明类B
class A
{
public:
int func(); //声明成员函数func()
};
class B
{
friend int A::func(); //声明类A的成员函数func()为友元函数
}
【示例2】通过案例演示类的成员函数作为其他类的友元函数的用法,C++ 代码如下:
#include<iostream>
#include<math.h>
using namespace std;
class Point;
class Circle
{
public:
float getArea(Point &p1,Point &p2); //声明计算面积的成员函数
private:
const float PI=3.14;
};
class Point
{
//声明类Circle的成员函数getArea()为友元函数
friend float Circle::getArea(Point &p1,Point &p2);
public:
Point(float x,float y);
~Point();
private:
float _x;
float _y;
};
Point::Point(float x=0,float y=0):_x(x),_y(y) //实现Point类的构造函数
{
cout<<"初始化坐标点"<<endl;
}
Point::~Point(){}
float Circle::getArea(Point &p1,Point &p2)
{
double x=abs(p1._x-p2._x); //获取横轴坐标间的距离
float y=abs(p1._y-p2._y); //获取纵轴坐标间的距离
float len=sqrtf(x*x+y*y); //计算两个坐标点之间的距离
cout<<"获取两个坐标点之间的距离是"<<len<<endl;
return len*len*PI; //友元函数访问私有成员变量PI
}
int main()
{
Point p1(5,5);
Point p2(10,10);
Circle circle;
float area=circle.getArea(p1,p2);
cout<<"圆的面积是:"<<area<<endl;
return 0;
}
运行结果:
初始化坐标点
初始化坐标点
获取两个坐标点之间的距离是7.07107
圆的面积是:157
- 第 4 行代码声明类 Point;
- 第 5~11 行代码定义了圆类 Circle;
- 第 12~22 行代码定义了坐标点类 Point,其中第 15 行代码将 Circle 类中的成员函数 getArea() 声明为友元函数;
- 第 28~35 行代码是 getArea() 函数的实现,函数的参数为 Point 类对象的引用,该函数计算两个坐标点距离的绝对值,然后以距离作为圆的半径,计算圆的面积后返回。其中,第 34 行在计算圆的面积时访问了 Circle 类中的私有成员 PI;
- 第 38~39 行代码初始化坐标点 p1 和 p2;
- 第 40~41 行代码,创建对象 circle,并通过对象 circle 调用友元函数 getArea() 计算圆的面积。
C++友元类
除了可以声明函数为类的友元函数,还可以将一个类声明为友元类,友元类可以声明在类中任意位置。声明友元类之后,友元类中的所有成员函数都是该类的友元函数,能够访问该类的所有成员。与声明友元函数类似,友元类也是使用关键字
friend 声明,其语法格式如下:
class B; //类B前向声明
class A
{
};
class B
{
friend class A; //声明类A是类B的友元类
}
【示例3】通过案例演示友元类的用法,C++ 代码如下:
#include<iostream>
using namespace std;
class Time //定义Time类,描述时分秒
{
public:
Time(int hour, int minute, int second); //声明有参构造函数
friend class Date; //声明类Date为友元类
private:
int _hour, _minute, _second;
};
class Date //定义Date类
{
public:
Date(int year, int month, int day); //声明有参构造函数
void showTime(Time& time); //声明显示时间的成员函数
private:
int _year, _month, _day;
};
Date::Date(int year, int month, int day) //实现Date类构造函数
{
_year = year;
_month = month;
_day = day;
}
void Date::showTime(Time& time)
{
cout << _year << "-" << _month << "-" << _day
<< " " << time._hour << ":" << time._minute
<< ":" << time._second << endl;
}
Time::Time(int hour,int minute,int second) //实现Time类构造函数
{
_hour = hour;
_minute = minute;
_second = second;
}
int main()
{
Time time(17,30,20); //创建Time对象
Date date(2019,10,31); //创建Date对象
date.showTime(time); //调用showTime()显示年月日、时分秒信息
return 0;
}
运行结果:
2021-9-26 11:36:20
示例分析:- 第 3~10 行代码定义了 Time 类,该类有三个成员变量 _hour、_minute 和 _second,分别表示时、分、秒;此外,Time 类还声明了 Date 友元类;
- 第 11~18 行代码定义了 Date 类,Date 类有三个成员变量 _year、_month 和 _day,分别用于表示年、月、日;
- 第 19~30 行代码在类外实现 Date 类的构造函数和成员函数 showTime();
- 第 31~36 行代码在类外实现 Time 类的构造函数;
- 第 39~40 行代码分别创建对象 time 和 date;
- 第 41 行代码通过对象 date 调用成员函数 showTime(),并以对象 time 作为参数。
使用友元应注意的地方
从面向对象程序设计来讲,友元破坏了封装的特性。但由于友元简单易用,因此在实际开发中较为常用,如数据操作、类与类之间消息传递等,可以提高访问效率。使用友元需要注意以下几点:
- 友元声明位置由程序设计者决定,且不受类中 public、private、protected 权限控制符的影响。
- 友元关系是单向的,即类 A 是类 B 的友元,但 B 不是 A 的友元。
- 友元关系不具有传递性,即类 C 是类 D 的友元,类 E 是类 C 的友元,但类 E 不是类 D 的友元。
- 友元关系不能被继承。
声明:《C++系列教程》为本站“54笨鸟”官方原创,由国家机构和地方版权局所签发的权威证书所保护。