1.友元
为了让类外的函数或另一个类,可以访问类中的私有成员,可以将它们声明为友元。
友元的声明只能出现在类定义的内部,以关键字friend声明。
友元可以是友元函数或友元类。
友元不是本类的成员,所以不受访问控制影响。
注意:友元的引入破坏了类的封装性和数据的隐藏性,请小心使用
2.友元函数
在类中将一个类外的普通函数,或其他类的成员函数声明为friend,就称为友元函数。
friend void display(Time &);
(1)将普通函数声明为友元函数
完整的程序:
#include<iostream>
using namespace std;
class Time {
public:
Time(int,int,int);
friend void display(Time &); //声明display为Time类的友元
private:
int hour;
int minute;
int sec;
};
Time::Time(int h,int m,int s) //构造函数
{ hour=h; minute=m; sec=s; }
void display(Time& t)
//友元不是Time类的成员,所以只能通过对象访问私有成员
{ cout<<t.hour<<":"<<t.minute<<":"<<t.sec<<endl; }
int main( )
{ Time t1(10,13,56);
display(t1); //调用display函数,实参t1是Time类对象
}
/
和如下程序等价:
1、增加公有方法,来使用私有变量
#include<iostream>
using namespace std;
class Time {
public:
Time(int,int,int);
int getHour(){return hour;}
int getMinute(){return minute;}
int getSec(){return sec;}
private:
int hour;
int minute;
int sec;
};
Time::Time(int h,int m,int s) //构造函数
{ hour=h; minute=m; sec=s; }
void display(Time& t)
//友元不是Time类的成员,所以只能通过对象访问公有方法
{ cout<<t.getHour()<<":"<<t.getMinute()<<":"<<t.getSec()<<endl; }
int main( )
{ Time t1(10,13,56);
display(t1); //调用display函数,实参t1是Time类对象
}
2、将函数变成类中的函数(如果该函数的参数表涉及到多个类,则不适合)
#include<iostream>
using namespace std;
class Time {
public:
Time(int,int,int);
void display(Time &);
private:
int hour;
int minute;
int sec;
};
Time::Time(int h,int m,int s) //构造函数
{ hour=h; minute=m; sec=s; }
void Time::display(Time& t)
{ cout<<t.hour<<":"<<t.minute<<":"<<t.sec<<endl; }
int main( )
{ Time t1(10,13,56);
t1.display(t1); //调用display函数,实参t1是Time类对象
}
(2)将另一个类的成员函数声明为友元
一个函数(普通函数或某个类的成员函数),可以被多个类声明为友元,这样就可以引用多个类中的私有数据。
完整的程序:
#include<iostream>
using namespace std;
class Date;
class Time {
public:
void display(Date &t) ;
};
class Date {
int year,month,day;
public:
Date(int y,int m,int d):year(y),month(m),day(d){}
friend void Time::display(Date &t);
};
void Time::display(Date &t)
{cout<<t.year<<"/"<<t.month<<"/"<<t.day<<endl;}
int main()
{
Date d(2016,4,12);
Time t;
t.display(d);
return 1;
}
不使用友元的改写方式:
1、增加公有函数获取私有数据:
#include<iostream>
using namespace std;
class Date;
class Time {
public:
void display(Date &t) ;
};
class Date {
int year,month,day;
public:
Date(int y,int m,int d):year(y),month(m),day(d){}
int getYear(){return year;}
int getMonth(){return month;}
int getDay(){return day;}
};
void Time::display(Date &t)
{cout<<t.getYear()<<"/"<<t.getMonth()<<"/"<<t.getDay()<<endl;}
int main()
{
Date d(2016,4,12);
Time t;
t.display(d);
return 1;
}
/
另一个例子:立方体碰撞
#include<iostream>
using namespace std;
class CCube;
class CPoint{
int x,y,z;
public:
CPoint(){}
CPoint(int x,int y,int z):x(x),y(y),z(z){}
int getx(){return x;}
int gety(){return y;}
int getz(){return z;}
friend int collide(CCube& r,CCube& r1);
};
class CCube{
CPoint *point;
public:
CCube(CPoint& a,CPoint& b){
point=new CPoint[2];
point[0]=a;
point[1]=b;
}
CCube(CCube& c){
point=new CPoint[2];
point[0]=c.point[0];
point[1]=c.point[1];
}
~CCube(){
delete[] point;
}
friend int collide(CCube& r,CCube& r1);
};
int collide(CCube& r,CCube& r1){
if(r.point[0].y>r1.point[1].y ||
r.point[1].y<r1.point[0].y ||
r.point[1].z>r1.point[0].z ||
r.point[0].z<r1.point[1].z ||
r.point[1].x<r1.point[0].x ||
r.point[0].x>r1.point[1].x)
return 0;
else
return 1;
}
int main(){
int t,x1,y1,z1,x2,y2,z2;
cin>>t;
while(t--){
cin>>x1>>y1>>z1>>x2>>y2>>z2;
CPoint a1(x1,y1,z1),b1(x2,y2,z2);
CCube c1(a1,b1);
cin>>x1>>y1>>z1>>x2>>y2>>z2;
CPoint a2(x1,y1,z1),b2(x2,y2,z2);
CCube c2(a2,b2);
if(collide(c1,c2))
cout<<"collide"<<endl;
else
cout<<"have distance"<<endl;
}
}
测试数据:
2
7 7 10 10 10 7
7 8 12 11 12 8
-1 -1 8 6 6 1
-10 -10 10 -8 -8 8
运行结果:
collide
have distance
3.友元类
如果需要把一个类(A类)中的所有成员函数都声明为另一个类(B类)的友元函数,可以直接把类A声明为类B的友元。
class A {
……
};
class B {
……
friend class A;
};
例子:
完整的程序:
#include<iostream>
using namespace std;
class Cylinder
{
double radius;
double height;
public:
Cylinder():radius(1),height(1){}
Cylinder(double r,double h=2):radius(r),height(h){}
void setRadius(double r){radius=r;}
void setHeight(double h){height=h;}
void display(){ cout<<"radius="<<radius<<",height="<<height<<endl;}
friend class A;
};
class A
{ public:
A(){}
void changeCylinder(Cylinder &c,double r,double h){
c.height=h;c.radius=r;
}
void display(Cylinder &c){
cout<<c.height<<" "<<c.radius<<endl;
}
};
int main()
{
Cylinder c(1,2);
c.display();
c.setHeight(10);
c.setRadius(8);
c.display();
A a;
a.changeCylinder(c,100,200);
a.display(c);
return 1;
}
/
不用友元类,改写程序:
#include<iostream>
using namespace std;
class Cylinder
{
double radius;
double height;
public:
Cylinder():radius(1),height(1){}
Cylinder(double r,double h=2):radius(r),height(h){}
void setRadius(double r){radius=r;}
void setHeight(double h){height=h;}
void display()
{ cout<<"radius="<<radius<<",height="<<height<<endl;}
double getRadius(){return radius;}
double getHeight(){return height;}
};
class A
{ public:
A(){}
void changeCylinder(Cylinder &c,double r,double h){
c.setHeight(h);
c.setRadius(r);
}
void display(Cylinder &c){
cout<<c.getHeight()<<" "<<c.getRadius()<<endl;
}
};
int main()
{
Cylinder c(1,2);
c.display();
c.setHeight(10);
c.setRadius(8);
c.display();
A a;
a.changeCylinder(c,100,200);
a.display(c);
return 1;
}
///
//
另一个例子:
#include<iostream>
using namespace std;
class Date;
class Time {
public:
void display(Date &t) ;
void setDate(Date &t,int y,int m,int d);
};
class Date {
int year,month,day;
public:
Date(int y,int m,int d):year(y),month(m),day(d){}
friend class Time;
};
void Time::display(Date &t)
{cout<<t.year<<"/"<<t.month<<"/"<<t.day<<endl;}
void Time::setDate(Date &t,int y,int m,int d)
{ t.year=y;t.month=m;t.day=d;}
int main()
{
Date d(2016,4,12);
Time t;
t.display(d);
t.setDate(d,2018,12,12);
t.display(d);
return 1;
}
//
#include<iostream>
using namespace std;
class Date;
class Time {
int hour,minute,second;
public:
Time(int h,int m,int s):hour(h),minute(m),second(s){}
friend class Date;
};
class Date {
int year,month,day;
Time t;
public:
Date(int y,int m,int d,Time t1):year(y),month(m),day(d),t(t1){}
void print()
{ cout<<year<<"/"<<month<<"/"<<day<<t.hour<<":"<<t.minute<<":"<<t.second<<endl;}
};
int main()
{
Time t(12,12,12);
Date d(2016,4,12,t);
d.print();
return 1;
}
(1)关于友元的说明
友元的关系
不具有交换性
,即友元关系具有
单向性。
友元的关系
不具有传递性
。
注意
:在实际工作中,除非确有必要,一般并不把整个类声明为友元类,而只将确实有需要的成员函数声明为友元函数,这样更安全一些。
(2)
关于友元利弊的分析
面向对象程序设计的一个
基本原则
是
封装性
和
信息隐蔽
,而
友元却可以访问
其他类中的私有成员
,不能不说这是对封装原则的一个小的破坏。
但是它能
有助于数据共享
,能
提高程序的效率
。在使用友元时,要注意到它的副作用,不要过多地使用友元,只有在使用它能使程序精炼,并能大大提高程序的效率时才用友元。
例子1:
include<iostream>
using namespace std;
class A
{ double a;
public:
A():a(0){}
A(double a1):a(a1){}
double add(A &r_a)
{ return a+r_a.a; }
double minus(A &r_a)
{ return a-r_a.a; }
~A(){}
friend double add(A& a1,A& a2);
friend double minus(A& a1,A& a2);
};
double add(A& a1,A& a2)
{ return a1.a+a2.a; }
double minus(A& a1,A& a2)
{ return a1.a- a2.a; }
int main()
{ A a1(2),a2(3);
cout<<a1.add(a2)<<endl;
cout<<a1.minus(a2)<<endl;
cout<<add(a1,a2)<<endl;
cout<<minus(a1,a2)<<endl;
return 1;
}
例子2:
#include<iostream>
using namespace std;
class A
{private:
double a;
public:
A():a(0){}
A(double a1):a(a1){}
double add(A &r_a)
{ return a+r_a.a; }
double minus(A &r_a)
{ return a-r_a.a; }
~A(){}
friend class B;
};
class B
{ public:
double add(A &r_a1,A &r_a2)
{ return r_a1.a+r_a2.a; }
double minus(A &r_a1,A &r_a2)
{ return r_a1.a-r_a2.a; }
};
int main()
{ A a1(2),a2(3);
cout<<a1.add(a2)<<endl;
cout<<a1.minus(a2)<<endl;
B b;
cout<<b.add(a1,a2)<<endl;
cout<<b.minus(a1,a2)<<endl;
return 1;
}
4.友元的实例讲解
判断两个圆的相对位置
第一步:分析类的结构
类
Point
:
数据:
x
坐标,
y
坐标
方法:构造方法,
set
方法,
get
方法
类
Circle
:
数据:圆心坐标,半径
方法:构造方法
类
Circle
的友元函数
judge
:
判断两个圆是否相交
第二步:定义类
测试数据:
2
1 1 2
2 2 3
1 1 1
5 5 1
/
完整的程序:
#include <iostream>
#include <cmath>
using namespace std;
class Point{
int x;
int y;
public:
Point(int x1=0,int y1=0):x(x1),y(y1){}
int getX(){return x;}
int getY(){return y;}
};
class Circle{
Point p;
int r;
public:
Circle(int x1,int y1,int r1):p(x1,y1),r(r1){}
friend void judge(Circle& c1,Circle& c2);
};
void judge(Circle& c1,Circle& c2){
double r=sqrt(pow((c1.p.getX()-c2.p.getX()),2)+pow((c1.p.getY()-c2.p.getY()),2));
if(r>c1.r+c2.r)
cout<<"not intersect"<<endl;
else
cout<<"intersect"<<endl;
}
int main()
{ int t,x,y,r;
cin>>t;
while(t--)
{
cin>>x>>y>>r;
Circle c1(x,y,r);
cin>>x>>y>>r;
Circle c2(x,y,r);
judge(c1,c2);
}
}
另一种方法
完整的程序:
#include <iostream>
#include <cmath>
using namespace std;
class Circle;
class Point{
int x;
int y;
public:
Point(int x1=0,int y1=0):x(x1),y(y1){}
int getX(){return x;}
int getY(){return y;}
friend void judge(Circle& c1,Circle& c2);
};
class Circle{
Point p;
int r;
public:
Circle(int x1,int y1,int r1):p(x1,y1),r(r1){}
friend void judge(Circle& c1,Circle& c2);
};
void judge(Circle& c1,Circle& c2){
double r=sqrt(pow((c1.p.x-c2.p.x),2)+pow((c1.p.y-c2.p.y),2));
if(r>c1.r+c2.r)
cout<<"not intersect"<<endl;
else
cout<<"intersect"<<endl;
}
int main()
{ int t,x,y,r;
cin>>t;
while(t--)
{
cin>>x>>y>>r;
Circle c1(x,y,r);
cin>>x>>y>>r;
Circle c2(x,y,r);
judge(c1,c2);
}
}