C++友元(课堂笔记)

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);
    }
}

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

荔枝啵啵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值