1.为什么要引用友元
提高程序运行效率,既减少了类型和安全性检查及调用时间的开销,但它破坏了类的封装型和隐藏性,使得非成员函数可以访问类的私有成员。
2.使用场景
1)运算符重载的某些场合;
2)2个类要共享数据
3)异类若想要访问private的数据,必须声明为友元
3.使用友元函数
友元函数是在类中使用关键字friend修饰的非成员函数。
由于友元函数不是成员函数,所以不存在this指针,必须通过对象来访问。
友元仅是打破了外部访问中的private的权限。A声明为B的友元,A就可以通过B的对象访问B的私有成员。
1)要访问非static成员,需要对象做参数;
2)要访问static成员或全局变量,则不需要对象做参数;
3)如果做参数的对象是全局对象,则不需要对象做参数;
友元函数的位置
是类外函数,所以它的声明可以放在类的私有段或公有段且没有区别。
友元函数的调用
可以直接调用友元函数,不需要通过对象或指针。
4.实战
4.1 普通函数做友元函数
class Pos
{
public:
friend Pos MovePos(Pos ¤t, Pos &move);
Pos(int x=0, int y=0, int angle=0)
:m_x(x)
,m_y(y)
,m_angle(angle)
{}
~Pos()
{}
void PrintPos()
{
cout << "current pos : ( " << m_x << ", " << m_y << ", " << m_angle << ")" << endl;
}
private:
int m_x;
int m_y;
int m_angle;
};
Pos MovePos(Pos ¤t, Pos &move)
{
Pos temp;
temp.m_x = current.m_x + move.m_x;
temp.m_y = current.m_y + move.m_y;
temp.m_angle = current.m_angle + move.m_angle;
return current;
}
int main()
{
Pos one(1,2,3);
Pos two(10,20,30);
Pos three = MovePos(one,two);
three.PrintPos();
return 0;
}
4.2 成员函数做友元函数
1)友元函数是其它类的成员函数
2)必须先定义包含成员函数的类(比如说A),再在另外一个类(比如说B)中将该成员函数声明为友元函数。此时虽然这个友元函数是A的成员函数,该友元函数仍然称为非成员函数(对于B来说)
前向声明:是一种不完全的类型(incomplete type)声明,即只需要提供类名(无需提供实现)即可。
特点:
1)不能定义对象
2)仅可用于定义指向这个类型的指针或引用
3)仅用于声明不是定义,仅可以作为形参类型或函数的返回值类型(定义在类外实现)
#include <iostream>
#include <cmath>
using namespace std;
//前向引用声明,否则报错 error: 'Point' does not name a type
class Point;
class Line{
public:
//这时不能使用这样的形式进行初始化:Line(Point p1,Point p2):p1(p1),p2(p2){}
//因为此时Point的结构尚未定义,error: field 'p1' has incomplete type
Line(Point p1,Point p2);
Point& getP1(); //把引用当做函数返回值
Point& getP2();
float dist();
private:
//不可以这样定义成员变量:Point p1,p2;因为此时Point结构尚不完善
Point &rp1,&rp2;//类(引用)的组合
//这里也可以用Point *rp1, *rp2;
//这样在构造函数时,可以不用传入Point的对象,而是在Line的构造函数中动态分配内存
//即
Line(int x, int y, int y, int y1){
rp1 = new Point(x, y);
rp2 = new Point(x1, y1);
}
};
class Point{
public:
Point(int x = 0,int y = 0):x(x),y(y){}
int getX(){ return x;}//内联函数
int getY(){ return y;}
void showData();
//声明友元成员函数
friend float Line::dist();
private:
int x,y;
};
void Point::showData(){
cout << "x: " << x << ", y: " << y << endl;
}
//Line类函数的延迟实现开始
//当一个类的成员变量是引用时,需要在初始化列表中初始化引用
//否则报错:error: uninitialized reference member
Line::Line(Point p1,Point p2):rp1(p1),rp2(p2){}
Point& Line::getP1(){
return rp1;
}
Point& Line::getP2(){
return rp2;
}
float Line::dist(){
double x = rp1.x - rp2.x;
double y = rp1.y - rp2.y;
return static_cast<float>(sqrt(x*x + y*y));
}
//Line类函数的延迟实现结束
int main()
{
Point p1(1,1),p2(4,5);
p1.showData();
p2.showData();
Line line(p1,p2);
cout << "the distance is : " << line.dist() << endl;
return 0;
}
4.3 友元类
#include <iostream>
#include <cmath>
using namespace std;
class Point{
public:
Point(int x = 0,int y = 0):x(x),y(y){}
int getX(){ return x;}//内联函数
int getY(){ return y;}
void showData();
//声明友元类,否则编译不通过,error: 'int Point::x' is private
friend class Line;
private:
int x,y;
};
void Point::showData(){
cout << "x: " << x << ", y: " << y << endl;
}
class Line{
public:
Line(Point p1,Point p2):p1(p1),p2(p2){}
Point getP1(){ return p1;}
Point getP2(){ return p2;}
float dist();
private:
Point p1,p2;//类的组合
};
float Line::dist(){
double x = p1.x - p2.x;
double y = p1.y - p2.y;
return static_cast<float>(sqrt(x*x + y*y));
}
int main()
{
Point p1(1,1),p2(4,5);
p1.showData();
p2.showData();
Line line(p1,p2);
cout << "the distance is : " << line.dist() << endl;
return 0;
}
5.友元性质
1)友元关系是不能传递的,如A是B的友元,B是C的友元,但A不是C的友元
2)友元关系是单向的,A是B的友元,A可以访问B的私有属性,反之不成立
3)友元关系是不被继承的,A是B的友元,但A的派生类不是B的友元