C++中的friend详细解析
C++中的友元机制允许类的⾮公有成员被⼀个类或者函数访问,友元按类型分为三种:普通⾮类成员函数作为友元,类的成员函数作为友元,类作为友元。友元包括友元的声明以及友元的定义。友元的声明默认为了extern,就是说友元类或者友元函数的作⽤域已经扩展到了包含该类定义的作⽤域,所以即便我们在类的内部定义友元函数也是没有关系的。
友元可以是⼀个函数,该函数被称为友元函数;友元也可以是⼀个类,该类被称为友元类。友元函数的特点是能够访问类中的私有成员的⾮成员函数。友元函数从语法上看,它与普通函数⼀样,即在定义上和调⽤上与普通函数⼀样。
的实现可以在类外定义,但必须在类内部声明
友元函数是可以直接访问类的私有成员的⾮成员函数。它是定义在类外的普通函数,它不属于任何类,
但需要在类的定义中加以声明,声明时只需在友元的名称前加上关键字friend。
我们已知道类具有封装和信息隐藏的特性。只有类的成员函数才能访问类的私有成员,程序中的其他函数是⽆法访问私有成员的。⾮成员函数可以访问类中的公有成员,但是如果将数据成员都定义为公有的,这⼜破坏了隐藏的特性。另外,应该看到在某些情况下,特别是在对某些成员函数多次调⽤时,由于参数传
递,类型检查和安全性检查等都需要时间开销,⽽影响程序的运⾏效率。
为了解决上述问题,提出⼀种使⽤友元的⽅案。友元是⼀种定义在类外部的普通函数,但它需要在类体内进⾏说明,为了与该类的成员函数加以区别,在说明时前⾯加以关键字friend。友元不是成员函数,但是它可以访问类中的私有成员。友元的作⽤在于提⾼程序的运⾏效率(即减少了类型检查和安全性检查等都需要的时间开销),但是,它破坏了类的封装性和隐藏性,使得⾮成员函数可以访问类的私有成员。
1.普通的⾮成员函数友元
{
public:
Point(double xx,double yy)
{
x=xx;
y=yy;
}
void GetXY();
system的头文件friend double Distance(Point &a,Point &b);
protected:
private:
double x,y;
};
void Point::GetXY()
{
//cout<<"("<<this->x<<","<<this->y<<")"<<endl;
cout<<"("<<x<<","<<y<<")"<<endl;
}
double Distance(Point &a,Point &b)
{
double length;
length=sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); //它可以引⽤类中的私有成员
return length;
}
int main(void)
{
Point p1(3.0,4.0),p2(6.0,8.0);
p1.GetXY(); //成员函数的调⽤⽅法,通过使⽤对象来调⽤
p2.GetXY();
double d = Distance(p1,p2); //友元函数的调⽤⽅法,同普通函数的调⽤⼀样,不要像成员函数那样调⽤
cout<<d<<endl;
system("pause");
return 0;
}
说明:在该程序中的Point类中说明了⼀个友元函数Distance(),它在说明时前边加friend关键字,标识它不是成员函数,⽽是友元函数。它的定义⽅法与普通函数定义⼀样,⽽不同于成员函数的定义,因为它不需要指出所属的类。但是,它可以引⽤类中的私有成员,函数体中的a.x,b.x,a.y,b.y都是类的私有成员,它们是通过对象引⽤的。在调⽤友元函数时,也是同普通函数的调⽤⼀样,不要像成员函数那样调⽤。本例中,p1.Getxy()和p2.Getxy()这是成员函数的调⽤,要⽤对象来表⽰。⽽Distance(p1, p2)是友元函数的调⽤,它直接调⽤,不需要对象表⽰,它的参数是对象。(该程序的功能是已知两点坐标,求出两点的距离。)
下⾯对上⾯的代码进⾏输⼊、输出流的重载:
{
public:
Point(double xx,double yy)
{
x=xx;
y=yy;
}
void GetXY();
friend double Distance(Point &a,Point &b);
friend ostream &operator <<(ostream &a,Point &b);
protected:
private:
double x,y;
};
// friend ostream& operator<<(ostream& o,A& another);
ostream &operator <<(ostream &out,Point &b) //在类中声明的时候,可以是ostream &a,函数定义的时候也可以是ostream &out
{
out<<"("<<b.x<<","<<b.y<<")"<<endl;
return out;
}
void Point::GetXY()
{
//cout<<"("<<this->x<<","<<this->y<<")"<<endl;
//cout<<"("<<x<<","<<y<<")"<<endl;
cout<<*this;
}
double Distance(Point &a,Point &b)
{
double length;
length=sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
return length;
}
int main(void)
{
Point p1(3.0,4.0),p2(6.0,8.0);
p1.GetXY();
p2.GetXY();
double d = Distance(p1,p2);
cout<<d<<endl;
system("pause");
return 0;
}
2.类作为友元
类作为友元需要注意的是友元类和原始类之间的相互依赖关系,如果在友元类中定义的函数使⽤到了原始类的私有变量,那么就需要在友元类定义的⽂件中包含原始类定义的头⽂件。但是在原始类的定义中(包含友元类声明的那个类),就不需要包含友元类的头⽂件.
另外,不需要在类定义前去声明友元类,因为友元类的声明⾃⾝就是⼀种声明。
//A.h
#pragma once
#include <iostream>
using namespace std;
class A
{
//friend class B; //如果不写这句话将会出现编译错误public:
~A(void);
A();
private:
int m_nItem;
};
//A.cpp
#include "A.h"
A::A()
{
m_nItem =3;
}
A::~A(void)
{
}
//B.h
#pragma once
class B
{
public:
B(void);
~B(void);
int func();
};
/
/B.cpp
#include "StdAfx.h"
#include "B.h"
#include "A.h" //must include A.h
#include <iostream>
B::B(void)
{
}
B::~B(void)
{
}
int B::func()
{
cout<<"This is in B"<<endl;
A a;
return a.m_nItem;
}
3.类成员函数作为友元函数
这个稍微有点复杂,因为你要类成员函数作为友元,你在声明友元的时候要⽤类限定符,所以必须先定义包含友元函数的类,但是在定义友元的函数时候,⼜必须事先定义原始类。通常的做法先定义包含友元函数的类,再定义原始类,这个顺序不能乱。(如果是友元类,则没有这种这种必须)如下⾯所⽰:
//A.h
#pragma once
#include "B.h"
class A
{
friend int B::func(A xx);
public:
A(void):mx(20),my(30){}
~A(void){}
private:
int mx;
int my;
};
/
/B.h
#pragma once
class A;
class B
{
public:
B(void);
~B(void);
int func(A xx);
};
//B.cpp
#include "B.h"
#include "A.h"
B::B(void)
{
}
B::~B(void)
{
}
int B::func(A xx)
{
* xx.my;
}
//main.cpp
#include "A.h"
#include "B.h"
#include <iostream>
using namespace std;
void main()
{
A a;
B b;
cout<<b.func(a)<<endl;
system("pause");
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论