c++ friend关键字

 

1.概述

目的: C++通过友元机制允许类的非公有成员被其它类或者非成员函数访问,友元按类型分:普通非类成员函数友元、它类成员函数友元、类友元

友元包括声明与定义。友元声明默认为了extern,就是说友元类或友元函数作用域已扩展至包含该类定义的作用域,即便在类的内部定义友元函数也没有关系。

2.普通非成员函数友元

 

语法与普通函数无异,友元函数不属于任何类,其实现可以在类外定义,但必在类内声明,声明需加friend关键字。

#include "cmath"

#include "iostream"

using namespace std;

class Point{

public:

      Point(double xx,double yy){ x=xx; y=yy;}

      void GetXY();

      friend double Distance(Point &a,Point &b);

protected:

private:

     double x,y;

};

void Point::GetXY(){ 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都是类的私有成员,它们是通过对象引用。

下面对上述代码进行输入、输出流符号重载:

#include <cmath>

#include <iostream>

using namespace std;

class Point{

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;

};

ostream &operator <<(ostream &out,Point &b)  {

     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 = 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;

}

3.类友元

类作为友元需要注意:友元类和原始类之间的相互依赖关系,如果在友元类中定义的函数访问原始类的私有变量,那么需要在友元类定义文件中包含原始类定义的头文件。但是在原始类的定义中(包含友元类声明的类),不需要包含友元类的头文件。 另外,不需要在类定义前去声明友元类,因为友元类的声明自身就是一种声明。

//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 "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;  //访问了A类的成员

4.它类成员函数友元

声明此种友元要用类限定符,因此必须先定义包含友元函数的类,但是在定义友元函数时候,又必须事先定义原始类。通常的做法先定义包含友元函数的类,再定义原始类,这个顺序不能乱(如果是友元类,则没有限制), 如下面所示:

//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,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){return xx.mx * 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");

}

5.其它

1. 友元只具单向性:若类B是类A友元,类A不一定是类B友元,要看类中是否有相应声明。

2. 友元不能被继承:B是A的友元类,C是B的子类,推不出C是A的友元。

3. 友元不具传递性:B是A的友元,C是B的友元,推不出C是A的友元。

posted @ 2019-06-23 21:54  Reboost  阅读(957)  评论(0)    收藏  举报