精华内容
下载资源
问答
  • 友元

    2021-06-12 07:56:17
    友元 友元是一种破坏类的封装性获取类的隐藏数据的方式。 如果有以下程序: class A { public: int Getx() { return x; } private: int x; }; class B { public: void Set(int y); private: A a; }; 上面就是类...

    友元

    友元是一种破坏类的封装性获取类的隐藏数据的方式。

    如果有以下程序:

    class A
    {
    public:
        int Getx()   { return x; }
    private:
        int x;
    };
    class B
    {
    public:
        void Set(int y);
    private:
        A a;
    };
    

    上面就是类的组合的形式。类B中包含一个类A的对象作为数据成员。但是类B的成员函数不能直接访问类A的私有数据成员x。

    比如下面类B的成员函数Set的实现是不正确的:

    void B::Set(int y)
    {
        a.x = y;
    }
    

    那么怎样实现B的成员函数直接访问A的数据成员呢?C++提供了友元机制。

    通过友元的方式,某个普通函数或者类的成员函数可以访问某个类中的私有数据,这样就等于在类的封装的很好的外衣上剪开了一个小洞,外界可以通过这个小洞访问到一些类内部的数据。

    友元提供了一种不同类或对象的成员函数之间、类的成员函数与普通函数之间共享数据的机制。

    它破坏了类的封装性和类数据的隐藏性,但是又给我们进行软件开发提供了很多方便,在我们实地进行软件开发的时候可以自己在共享和封装之间平衡一下,决定是否选择使用友元,原则上尽量少使用或不使用友元,除非确实很大的提高了开发效率。

    在一个类中声明友元的方式是,用关键字friend把普通函数、其他类的成员函数或其他类声明为此类的友元,用friend声明的元素就可以访问此类的私有数据。

    如果友元是普通函数或是类的成员函数就叫做友元函数,如果友元是一个类则叫做友元类,友元类的所有成员函数均为友元函数。

    友元函数

    友元函数是在类的声明中用关键字friend修饰的普通函数或者其他类的成员函数。友元函数虽不是本类的成员函数,但在它的函数体中可以访问该类对象的私有成员和保护成员。

    给大家看个例子:

    #include <iostream>
    #include <math.h>
    using namespace std;
    class Data //Data类声明
    {
    public:      //外部接口
        Data(int xx=0) { x=xx; }
        int GetX() { return x; }
        friend int Add(Data &a, Data &b);
    private: //私有数据成员
        int x;
    };
    int Add(Data &a, Data &b)
    {
        return a.x + b.x;
    }
    int main()
    {
        Data a(1);
        Data b(2);
        int sum = Add(a, b);
        cout<<"The sum is "<<sum<<endl;
        return 0;
    }
    

    在这里插入图片描述
    在Data类中声明友元函数Add时只给出了友元函数原型,友元函数Add的实现在类Data外。我们看到,在Add函数体中直接通过对象名访问了Data类的私有成员x,这就是友元的强大作用。

    我们在类外用一般方式访问x的话必须通过公共接口GetX来实现,若要访问的私有成员很多或者要访问的地方很多就要多次调用函数,对于我们写代码和程序运行都有效率上的损失,但是用友元也有个很大的缺点就是,如果私有数据x发生结构性的变化,那么友元函数就要做相应的修改,所有调用友元函数的地方可能也要修改,这就降低了开发效率,所以是否要使用友元可以自己权衡。

    友元类

    类也可以声明为另一个类的友元,就像友元函数那样,这个作为另一个类的友元的类就叫做友元类。

    如果一个类B是类A的友元类,则类B的所有成员函数都是类A的友元函数,都能访问类A的私有成员和保护成员。

    友元类的声明形式为:

    class A
    {
          ...
          friend class B;   // 将类B声明为类A的友元类
          ...
    }
    

    上面声明中,类B是类A的友元类,B的成员函数可以访问类A的对象的私有成员和保护成员。

    再让大家看看友元类的使用:

    class A
    {
    public:
        void Display()   { cout<<x<<endl;}
        friend class B;
    private:
        int x;
    }
    class B
    {
    public:
        void Set(int i);
        void Display();
    private:
        A a;
    };
    void B::Set(int i)
    {
        a.x=i;        // 因为类B是类A的友元类,所以类B的成员函数可以访问类A对象的私有成员
    }
    void B::Display()
    {
        a.Display();
    }
    

    友元关系不能传递,如果类B是类A的友元,类C又是类B的友元,类C和类A如果没有声明则没有友元关系,另外,友元关系是单向的,如果类B是类A的友元,类B的成员函数可以访问类A对象的私有成员和保护成员,但是类A的成员函数不能访问类B对象的私有成员和保护成员。

    展开全文
  • 友元的作用:允许让友元类(友元函数)访问自己的私有属性 友元的创建方式:在类的声明(函数的声明)前面加上友元关键字friend,放在允许被访问私有属性的类的里面(不受访问权限限制,随便放,只不过一般我们放在...

    友元的作用:允许让友元类(友元函数)访问自己的私有属性
    友元的创建方式:在类的声明(函数的声明)前面加上友元关键字friend,放在允许被访问私有属性的类的里面(不受访问权限限制,随便放,只不过一般我们放在类的最上面)。

    一、全局函数做类的友元函数

    class Building
    {
    	friend void visit1(Building building);//visit1函数在类里面被声明为友元类
    	friend void visit2(Building& building);//visit2函数在类里面被声明为友元类
    public:
    	Building()
    	{
    		parlor = "客厅";
    		bathroom = "卧室";
    	}
    	void Print_bathroom()
    	{
    		cout << "bathroom:" << bathroom << endl;
    	}
    public:
    	string parlor;
    private:
    	string bathroom;
    };
    
    void visit1(Building building)//临时对象访问私有属性
    {
    	cout << "visit1正在访问bathroom:" << building.bathroom << endl;
    }
    
    void visit2(Building& building)//原对象在友元函数里访问私有属性
    {
    	cout << "visit2正在访问bathroom:" << building.bathroom << endl;//error
    	building.bathroom = "卧室2";
    }
    
    int main()
    {
    	Building building;
    
    	visit1(building);
    	building.Print_bathroom();
    
    	visit2(building);
    	building.Print_bathroom();//building私有属性在visit2函数里面已经被修改
    	
    	return 0;
    }
    

    在这里插入图片描述

    总结来说,不管是在主函数里创建的对象还是在友元全局函数里创建的临时对象,在友元全局函数里对象都可以为所欲为,可以随意访问私有属性,甚至对象在里面可以修改自己的私有属性。
    也就是说,除了友元全局函数没有this指针之外,友元函数和类的成员函数对于类来说没什么区别。所以慎用友元。

    二、一个类的成员函数做另一个类的友元函数

    作用:让一个类的成员函数可以访问另一个类的私有属性。

    class Building
    {
    public:
    	Building()
    	{
    		parlor = "客厅";
    		bathroom = "卧室";
    	}
    public:
    	string parlor;
    private:
    	string bathroom;
    };
    
    class Breather
    {
    public:
    	Breather()
    	{
    		building = new Building;
    	}
    	string Get_bathroom()
    	{
    		return building->bathroom;
    	}
    	Building* building;
    };
    

    上面的代码是不允许的。Get_bathroom()函数会报错,原因是Building的bathroom为私有属性,Buildine类的对象不能访问。那么我们如果允许这函数访问呢?那就告诉Building类,这个Get_bathroom函数为友元函数。
    但是一个类的成员函数做另一个类的友元函数这个过程是屡屡碰壁的!
    首先我们来看第一种代码:

    class Building
    {
    public:
    	friend string Breather::Get_bathroom();//将类Breather的成员函数Get_bathroom()声明为Building的友元函数
    	Building()
    	{
    		parlor = "客厅";
    		bathroom = "卧室";
    	}
    public:
    	string parlor;
    private:
    	string bathroom;
    };
    
    class Breather
    {
    public:
    	Breather()
    	{
    		building = new Building;
    	}
    	string Get_bathroom()
    	{
    		return building->bathroom;
    	}
    	Building* building;
    };
    

    这种代码编译器通不过,看一下运行结果:
    在这里插入图片描述
    先抛开访问权限问题,第二个问题说Breather不是类或命名空间名称,这个问题很好想,因为我们在类Breather定义和声明前就用它了,编译器不知道这是什么东西,那么我们平常解决办法就是提前声明一下。那么我们在最上面加上class Breather;声明后,再运行出现以下问题:
    在这里插入图片描述
    这个问题应该是找不到Get_bathroom(),那么我们干脆直接把Breather类放在Building类之前定义。那么就在最前面加上class Breather;声明Breather是一个类。修改后代码如下:

    class Building;
    
    class Breather
    {
    public:
    	Breather()
    	{
    		building = new Building;
    	}
    	string Get_bathroom()
    	{
    		return building->bathroom;
    	}
    	Building* building;
    };
    
    class Building
    {
    public:
    	friend string Breather::Get_bathroom();
    	Building()
    	{
    		parlor = "客厅";
    		bathroom = "卧室";
    	}
    public:
    	string parlor;
    private:
    	string bathroom;
    };
    

    运行结果:
    在这里插入图片描述
    人傻了,先不说一直报错的另一个问题(bathroom不可访问,这个问题说明我们友元没有弄成功),就连这两个类的类名都搞定不了了。冷静一下之后,突然想明白了。
    首先再来仔细来分析一下,第23行代码用到了类Building的构造函数,我们只是声明了Building是一个类,但是编译器这个时候并不知道这个类里面有什么东西,所以没办法调用Building的构造函数,所以building没办法构造出来,所以23行和27行都报错。那么,我们就把类Breather中用到Building类及Building构造的对象的语句都放在最后面,放到Building类的后面,这样到时候编译器就已经知道Building类里面有什么东西了。修改后的代码:

    class Breather;
    class Building;
    
    class Breather
    {
    public:
    	Breather();//只留声明,定义放到类Building下面
    	string Get_bathroom();//只留声明,定义放到类Building下面
    	Building* building;
    };
    
    class Building
    {
    public:
    	friend string Breather::Get_bathroom();
    	Building()
    	{
    		parlor = "客厅";
    		bathroom = "卧室";
    	}
    public:
    	string parlor;
    private:
    	string bathroom;
    };
    
    /**************Breather类中用到类Building的两个函数定义***************/
    Breather::Breather()
    {
    	building = new Building;
    }
    string Breather::Get_bathroom()
    {
    	return building->bathroom;
    }
    /******************************************************************/
    int main()
    {
    	Breather breather;
    	breather.Get_bathroom();
    
    	return 0;
    }
    

    运行结果:
    在这里插入图片描述
    终于成功了!

    类的成员函数做另一个类的友元函数,总结来说注意以下几点:
    1.成员函数被做友元的类,写在另一个类的上面。
    2.另一个类的声明写在成员函数被做友元的类的上面。(为了简单,可把所有类都在最上面声明一下)。
    3.所有用到其他类的成员的函数的定义都写在其他类的下面。(在本来的类中肯定要写声明)。

    三、一个类做另一个类的友元类

    class Building
    {
    	friend class Breather;//声明Breather为友元类
    public:
    	Building()
    	{
    		parlor = "客厅";
    		bathroom = "卧室";
    	}
    public:
    	string parlor;
    private:
    	string bathroom;
    };
    
    class Breather 
    {
    public:
    	Breather()
    	{
    		building = new Building;
    	}
    	string Get_bathroom()
    	{
    		return building->bathroom;
    	}
    	Building* building;
    };
    
    void visit1(Breather& breather)
    {
    	cout << "breaather 正在访问:" << breather.building->parlor << endl;
    	//cout << "breaather 正在访问:" << breather.building->bathroom << endl;//error1
    }
    
    int main()
    {
    	Breather breather;
    
    	cout << "正在访问:" << breather.building->parlor << endl;
    	//cout << "正在访问:" << breather.building->bathroom << endl;//error
    	cout << "正在访问:" << breather.Get_bathroom() << endl;
    	visit1(breather);
    
    	return 0;
    }
    

    运行结果:
    在这里插入图片描述

    以上面代码为例,总结来说,就是Building创建的对象在Breather类里面可以为所欲为,可以随意访问和修改自己的私有属性,但是在Breather类外面不可以这样做,哪怕是以Breather类为中介创建的Building的对象。
    友元函数作用是在这个友元函数内,Building的对象可以为所欲为;友元类作用是在这个友元类内,Building的对象可以为所欲为。在类外除非调用这两个类的成员函数,否则无法继续访问Building的私有属性。

    上面代码发现visit函数里不可以直接访问Building的私有属性,但是如果把visit声明为友元函数,那么在visit里面这些对象也可以为所欲为了。下面代码是把Breather声明为友元类,把visit函数声明为友元函数:

    class Building
    {
    	friend class Breather;//将Breather声明为友元类
    	friend void visit1(Breather& breather);//将visit1声明为友元函数
    public:
    	Building()
    	{
    		parlor = "客厅";
    		bathroom = "卧室";
    	}
    	string Get()
    	{
    		return bathroom;
    	}
    public:
    	string parlor;
    private:
    	string bathroom;
    };
    
    class Breather 
    {
    public:
    	Breather()
    	{
    		building = new Building;
    	}
    	string Get_bathroom()
    	{
    		return building->bathroom;
    	}
    	Building* building;
    };
    
    void visit1(Breather& breather)
    {
    	cout << "breather 正在访问:" << breather.building->parlor << endl;
    	cout << "breather 正在访问:" << breather.building->bathroom << endl;
    }
    
    int main()
    {
    	Breather breather;
    	visit1(breather);
    
    	return 0;
    }
    

    运行结果:
    在这里插入图片描述
    visit1声明为Building的友元函数,对象在里面可以为所欲为。那么如果在Breather类为Building类的友元类的前提下,在Breather类里面将visit1声明为友元函数,那么在visit1里面可以用breather.building->bathroom吗?如下代码:

    class Building
    {
    	friend class Breather;//将Breather类声明为Building的友元类
    public:
    	Building()
    	{
    		parlor = "客厅";
    		bathroom = "卧室";
    	}
    	string Get()
    	{
    		return bathroom;
    	}
    public:
    	string parlor;
    private:
    	string bathroom;
    };
    
    class Breather 
    {
    	friend void visit1(Breather& breather);//将visit1声明为友元Breather的函数
    public:
    	Breather()
    	{
    		building = new Building;
    	}
    	string Get_bathroom()
    	{
    		return building->bathroom;
    	}
    	Building* building;
    };
    
    void visit1(Breather& breather)
    {
    	cout << "breaather 正在访问:" << breather.building->parlor << endl;
    	cout << "breaather 正在访问:" << breather.building->bathroom << endl;//error!!!!!!!!!!!
    }
    
    int main()
    {
    	Breather breather;
    	visit1(breather);
    
    	return 0;
    }
    
    

    答案是不可以!
    捋一下关系:Breather为Building的友元类,visit1为Breather的友元函数。所以在Breather类里面,Building类的对象可以为所欲为,在visit1函数里面,Breather类的对象可以为所欲为。
    友元赋予的权限不具有传递性。
    在visit1里面Breather类的对象可以为所欲为,但是不能够用Breather类的对象为中介去调用Building类的对象为所欲为。

    展开全文
  • 学习了c++这么久,一直没有对友元进行了解,据说友元不是特别好用(据说,不是我说的),因此直到今天才去了解。其实友元确实不是很常用,但友元功能确实很实用,它不但能够释放类中的非公有成员,同时还能保证了类的...

    学习了c++这么久,一直没有对友元进行了解,据说友元不是特别好用(据说,不是我说的),因此直到今天才去了解。其实友元确实不是很常用,但友元功能确实很实用,它不但能够释放类中的非公有成员,同时还能保证了类的封装性。用户可以有选择为具体的类或函数赋予“通行证”。还是比较灵活的。比如:某个类去访问另一个类的私有成成员,或者一个函数去访问某个类的私有成员等等,都可以使用友元来实现。

    下面就友元做了两个小例子,望高手指教。(每段代码都在不同的文件中)

    首先是关于友元类的代码,就一句话,很简单。。。

    Test.h:

    #ifndef TEST_H

    #define TEST_H

    #include

    using namespace std;

    class Test

    {

    friend class FriendTest; //此处声明FriendTest为Test的友元类,FriendTest类可以访问Test的私有成员

    public:

    Test();

    void set(int h,int w);

    void print();

    virtual ~Test();

    protected:

    private:

    int height;

    int weight;

    };

    #endif // TEST_H

    Test.cpp

    #include "../include/Test.h"

    Test::Test()

    {

    //ctor

    height = 0;

    weight = 0;

    }

    void Test::set(int h, int w)

    {

    height = h;

    weight = w;

    }

    void Test::print()

    {

    cout << height << " ";

    cout << weight <

    }

    Test::~Test()

    {

    //dtor

    }

    下面关于FriendTest的相关程序。

    FriendTest.h

    #ifndef FRIENDTEST_H

    #define FRIENDTEST_H

    #include "Test.h"

    class FriendTest

    {

    public:

    FriendTest();

    void setTest(Test& t, int h, int w);

    virtual ~FriendTest();

    protected:

    private:

    };

    #endif // FRIENDTEST_H

    FriendTest.cpp

    #include "../include/FriendTest.h"

    FriendTest::FriendTest()

    {

    //ctor

    }

    void FriendTest::setTest(Test& t, int h, int w) //之前声明了友元,所以此处可以调用私有成员

    {

    t.height = h;

    t.weight = w;

    }

    FriendTest::~FriendTest()

    {

    //dtor

    }#include

    #include "./include/Test.h"

    #include "./include/FriendTest.h"

    using namespace std;

    int main()

    {

    Test t;

    FriendTest ft;

    t.set(30, 20);

    ft.setTest(t,9,8);

    t.print();

    return 0;

    }

    接下来是关于友元函数的问题,友元函数我弄了很久,对于某个类来说,只希望其某个函数为友元,需要对函数进行友元声明。然而将上边代码中的友元类的声明改成友元函数的声明,编译不通过,提示未定义。后来发现对于友元函数来说两个类必须放在同一个文件中,并且要有部分调整,具体实现如下,并富有详解。

    部分代码省略。。。主要代码如下:

    #include

    using namespace std;

    //由于两个类都使用到了另一个类,所以顺序很关键。如果将两个类的顺序颠倒会出现编译不通过,并提示未定义。另外友元函数必须在最后实现,因为它用到了两个类中的成员。仔细与上一部分的代码比较,你便会了解里边的玄机。。。

    class Test; //首先需要声明Test类,FriendTest类中需要使用。

    class FriendTest

    {

    public:

    FriendTest();

    void setTest(Test& t, int h, int w);

    virtual ~FriendTest();

    protected:

    private:

    };

    class Test

    {

    friend void FriendTest::setTest(Test& t, int h, int w); //友元函数声明

    public:

    Test();

    void set(int h,int w);

    void print();

    virtual ~Test();

    protected:

    private:

    int height;

    int weight;

    };

    void FriendTest::setTest(Test& t, int h, int w)

    {

    t.height = h;

    t.weight = w;

    }

    int main()

    {

    cout << "friend" <

    Test t;

    FriendTest ft;

    t.set(30, 20);

    ft.setTest(t,9,8);

    t.print();

    return 0;

    }

    另外在网上看到了一个关于primer c++中一个友元例子的讲解可能对你理解有些帮助:

    做了部分修改。。。。。。

    第一种写法问题:

    编译到Screen时,由于Screen类使用到Window_Mgr的成员函数,前面给出了Window_Mgr的声明,但不清楚Window_Mgr的完整定义,对成员函数不清楚,所以友元函数声明不成立,编译出错。

    class Window_Mgr

    class Screen

    {

    public:

    friend Window_Mgr& Window_Mgr::relocate(Window_Mgr::index r, Window_Mgr::index c, Screen& s);

    private:

    int height;

    int width;

    }

    class Window_Mgr

    {

    public:

    typedef std::string::size_type index;

    Window_Mgr& Window_Mgr::relocate(index r, index c, Screen& s)

    {

    s.height += r;

    s.width += c;

    return *this;

    }

    }

    第二种写法问题在于:

    编译到relocate时,由于Screen& s的实现使用到Screen的成员变量,虽然前面给出了Screen的声明,但此时还不清楚Screen的完整定义,所以编译出错。

    class Screen;

    class Window_Mgr

    {

    public:

    typedef std::string::size_type index;

    Window_Mgr& Window_Mgr::relocate(index r, index c, Screen& s)

    {

    s.height += r;

    s.width += c;

    return *this;

    }

    }

    class Screen

    {

    public:

    friend Window_Mgr& Window_Mgr::relocate(Window_Mgr::index r, Window_Mgr::index c, Screen& s);

    private:

    int height;

    int width;

    }

    第三种写法:

    将Window_Mgr::relocate的实现移动到最后,由于编译类Window_Mgr时,并不需要Screen&s 的实现细节,问题得到解决

    class Screen;

    class Window_Mgr

    {

    public:

    typedef std::string::size_type index;

    Window_Mgr& Window_Mgr::relocate(index r, index c, Screen& s);   //无内部成员的使用

    }

    class Screen

    {

    public:

    friend Window_Mgr& Window_Mgr::relocate(Window_Mgr::index r, Window_Mgr::index c, Screen& s);

    private:

    int height;

    int width;

    }

    Window_Mgr& Window_Mgr::relocate(Window_Mgr::index r, Window_Mgr::index c, Screen& s)

    {

    s.height += r;

    s.width += c;

    return *this;

    }

    可见,这两个类如果编译成功需要严格的交替顺序

    这也就解释了为什么放在两个文件中无法编译。

    附录:

    一开始的实现的不能编译的两个文件

    实现分别如下:Window_Mgr.h

    #ifndef WINDOW_MGR //为了避免两个文件嵌套

    #define WINDOW_MGR

    #include

    #include

    class Window_Mgr

    {

    public:

    typedef std::string::size_type index;

    Window_Mgr& Window_Mgr::relocate(index r, index c, Screen& s)

    {

    s.height += r;

    s.width += c;

    return *this;

    }

    }

    #endif

    Screen.h

    #ifndef SCREEN

    #define SCREEN

    #include "Window_Mgr.h"

    class Screen

    {

    public:

    friend Window_Mgr& Window_Mgr::relocate(Window_Mgr::index r, Window_Mgr::index c, Screen& s);

    private:

    int height;

    int width;

    }

    #endif

    展开全文
  • 一、友元函数友元函数是一种特殊的函数,它需要在类体内进行说明,可以访问类的私有成员和保护成员,但又不是类的成员函数。友元函数的说明如下:friend 数据类型函数名(参数)其中,friend是说明友元函数的关键字,...

    af418581e80ee46ab8edbe9e564d37f7.png

    一、友元函数

    友元函数是一种特殊的函数,它需要在类体内进行说明,可以访问类的私有成员和保护成员,但又不是类的成员函数。友元函数的说明如下:

    friend 数据类型函数名(参数)

    其中,friend是说明友元函数的关键字,友元声明可以出现在类中的任何地方。通常,将友元声明成组地放在类定义的开始或结尾是个好主意。归纳起来,友元函数是一种能够访问类中私有成员的非类成员函数,友元函数在定义上和调用上与普通函数一样。友元的作用在于提高程序的运行效率,但是,它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。因此,只有在十分需要的时候才使用友元函数。 例如:分析下面程序的输出结果

    #include

    #include

    using namespace std;

    class TPoint

    {

    private:

    double x,y; //私有数据成员

    public:

    TPoint(double a,double b) //构造函数

    {

    x=a,y=b;

    cout<

    }

    friend double distanceoftwopoints(TPoint &a, TPoint &b) //友元函数

    {

    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));

    }

    } ;

    int main()

    {

    TPoint p1(2,2),p2(5,5);

    cout<

    return 0;

    }

    上述程序中,distaceoftwopoints()是类TPoint的友元函数,在其中可以直接使用a.x等,由于x等是类TPoint的私有成员,所以在普通函数中是不能这么使用的,但是在友元函数中则可以。下面是该程序的输出。

    9eb52dbc6d53aaa00fbc7ec25e70b006.gif

    友元函数的一个重要特点是它可以是多个类的友元。例如,编写一个程序,求一个点到直线的距离。设计一个点类Point,它有两个私有数据成员x和y,表示点的坐标。另一个类为直线类Line,它有三个私有数据成员a,b和c,表示直线方程ax+by+c=0。这两个类中都说明了一个友元函数dist,用于计算一个点到直线的距离。点(x,y)到直线ax+by+c=0的距离d的计算公式如为:d=abs((ax+by+c)/sqrt(a* a+b*b)),其中abs是求绝对值函数,sqrt是求平方根函数。代码如下:

    #include

    #include

    using namespace std;

    class Line;//提前说明

    class Point

    {

    int x,y;

    public:

    Point(int x1,int y1)

    {

    x=x1; y=y1;

    }

    friend double dist(Line l, Point p);//友元函数说明

    } ;

    class Line

    {

    int a,b,c;

    public:

    Line(int a1, int b1, int c1)

    {

    a=a1; b=b1; c=c1;

    }

    friend double dist(Line l, Point p);//友元函数说明

    };

    double dist(Line l, Point p)//注意:类内已经说明,因此函数前不要加friend

    {

    double d;

    d = abs(l.a*p.x+l.b*p.y+l.c)/(sqrt(l.a*l.a+l.b*l.b));

    return d;

    }

    int main()

    {

    Point p(10,10);

    Line l(2,4,-3);

    cout<

    return 0;

    }

    下面是该程序的输出结果:上述程序中有两个类Point和Line,它们都说明了同一个友元函数:friend double dist(Line l, Point p)。由于在Point类中说明时尚未定义类Line,所以需要在前面用class Line语句进行提前说明。该程序的执行如下:

    7726b4b19e263c1a9b9b5b9a1a301c63.gif

    一个类A的成员 函数f()可以作为另一个类B的友元函数,在这种情况下,必须先定义A类,并且在B类中说明友元函数f()时,要加上成员函数所在类的类名,即:

    class A

    {

    ...

    数据类型 f(参数表)

    ...

    }

    class B

    {

    ...

    friend 数据类型 A::f(参数表);

    ...

    }

    数据类型 A::f(参数表)

    {

    函数体;

    }二、友元类

    除了前面所讲过的友元函数外,友元还可以是一个类,即一个类可以作为另一个类的友元。当一个类作为另外一个类的友元时,就意味着这个类的所有成员函数都是另一个类的友元函数。例如,以下程序说明类B是类A的友元类:

    class A

    {

    ...

    Public:

    friend class B;//说明B是A的友元类

    ...

    }

    例如,有如下程序

    #include

    #include

    using namespace std;

    class A

    {

    int x;

    public:

    A() {x=5;}

    friend class B;//说明B是A的友元类

    };

    class B

    {

    public:

    void disp1(A tmp){

    tmp.x++;

    cout<

    }

    void disp2(A tmp){

    tmp.x--;

    cout<

    }

    };

    int main()

    {

    A obj1;

    B obj2;

    obj2.disp1(obj1);

    obj2.disp2(obj1);

    return 0;

    }

    }

    上述程序中,类B是类A的友元类,类B包括两个成员函数,这两个成员函数可以当成类A自己的友元函数一样使用,该程序执行结果如下:

    788942a6c8886aec9b819f8790eb4d9b.gif

    友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。当希望一个类可以存取另一个类的私有成员时,可以将该类声明为另一类的友元类。关于友元类的注意事项:(1)友元关系不能被继承。(2)友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。(3)友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明。

    三、习题解析

    1.一个类的友元函数能够访问该类的( )。A.私有成员 B.保护成员 C.公有成员 D.所有成员

    解析:一个类的友元函数对类成员的访问能力等同于类的成员函数,即能访问类的所有成员,选D。

    2.下列的各类函数中,( )不是类的成员函数。A、 构造函数 B、析构函数 C、友元函数 D、拷贝初始化构造函数

    答案:C

    3.下列关于友元的描述中,错误的是( )A.友元函数可以访问该类的私有数据成员B.一个类的友元类中的成员函数都是这个类的友元函数C.类与类之间的友元关系可以继承D.友元可以提高程序的运行效率

    解析:友元关系是不能被继承的,并且是单向的,不可交换的。

    4.下列程序利用友元函数求2个点的距离,找出存在的错误(有2个错)。

    #include

    #include

    class Tpoint

    { double x,y;

    public:

    Tpoint(double a,double b)

    { x=a; y=b; }

    friend double distance(Tpoint &, Tpoint &);

    };

    double Tpoint::distance(Tpoint &p1,Tpoint &p2)

    { double dist;

    dist=sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));

    return dist;

    }

    int main()

    { Tpoint p1(2,2),p2(5,6);

    cout<

    return 0;

    }四、小结

    在需要允许某些特定的非成员函数访问一个类的私有成员(及受保护成员),而同时仍阻止一般的访问的情况下,友元是可用的。

    优点:可以灵活地实现需要访问若干类的私有或受保护的成员才能完成的任务;便于与其他不支持类概念的语言(如C语言、汇编等)进行混合编程;通过使用友元函数重载可以更自然地使用C++语言的IO流库,便于实现运算符的重载等功能。

    缺点:一个类将对其非公有成员的访问权限授予其他函数或者类,会破坏该类的封装性,降低该类的可靠性和可维护性。

    参考书目

    《C++ Primer》,《C++语言习题与解析》等

    展开全文
  • 友元函数和友元

    2021-05-26 22:40:49
    友元的概念: 遵循一定规则而使对象以外的软件系统能够不经过消息方式而直接访对象内封装的数据成员的技术方法便是友元友元是面向对象系统与过程系统衔接纽带。 友元有:友元函数,友元成员,友元友元可以...
  • 一、友元介绍我们知道,类的成员函数可以访问同类的其他成员函数,包括公有、私有和保护成员。而类的外部函数只能访问类的公有成员。友元是一种允许非类成员函数访问类的非公有成员的一种机制。可以把一个函数指定为...
  • 友元函数 在c++中对类的成员设置了保护,如private和protected是不允许外部访问的,有时候有一个外部函数就是需要访问,为了解决这个问题,c++开了个后门,就是友元函数,友元函数就是将外部函数在类中进行申明,...
  • 现在,我们来介绍一种例外情况——友元(friend)。借助友元(friend),可以使得其他类中的成员函数以及全局范围内的函数访问当前类的 private 成员。friend 的意思是朋友,或者说是好友,与好友的关系显然要比一般...
  • 除了友元函数外,还有友元类,两者统称为友元友元的作用是提高了程序的运行效率(即减少了类型检查和安全性检查等都需要时间开销),但它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。 友元...
  • 友元与静态成员

    2020-12-19 09:07:24
    (6)C++友元与静态成员 (一)友元友元是访问类私有成员的一种途径.友元包括友元函数和友元类. 2.1友元函数  在C++中友元函数允许在类外访问该类中的任何成员,就像成员函数一样,友元函数用关键字friend说明....
  • C++ 语言访问控制 - 友元 (friend) 在 C++ 语言中,我们使用访问说明符 (access specifiers) 加强类的封装性: 定义在 public 说明符之后的成员在整个程序内可被访问,public 成员定义类的接口。 定义在 private ...
  • 友元函数 在定义一个类的时候,可以把一些函数(包括全局函数和其他类的成员函数)声明为“友元”,这样那些函数就成为该类的友元函数,在友元函数内部就可以访问该类对象的私有成员了。 将全局函数声明为友元的...
  • c++友元类和友元函数

    2021-05-06 16:10:28
    一、友元函数 友元函数和普通函数最大的区别在于友元函数可以直接访问类的私有成员和保护成员; 友元函数不属于类的成员函数,但是友元函数必须在类内部定义; 友元函数使用friend关键词声明; 友元函数能够实现类...
  • 若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明 inline 避免了频繁调用函数对栈内存重复开辟所带来的消耗,比如递归函数,inline仅是一个对编译器的建议 inline的使用是有所...
  • C++中的友元函数

    2021-05-13 02:49:54
    1为什么要使用友元函数在实现类之间数据共享时,减少系统开销,提高效率。如果类A中的函数要访问类B中的成员(例如:智能指针类的实现),那么类A中该函数要是类B的友元函数。具体说:为了使其他类的成员函数直接访问...
  • C++:成员友元函数(成员函数友元化) 友元函数 友元函数是指某些虽然不是类成员却能够访问类的所有成员的函数。类授予它的友元特别的访问权。 友元函数既可以是不属于任何类的非成员函数(全局函数),也可以是另一...
  • 1. 友元函数 1)友元函数是个函数,只要让普通函数func声明为类A的友元函数,那么func这个函数就能访问类A的所有成员(成员变量、成员函数),无论是public,private,protected 2)由于友元函数不属于类成员,所以...
  • 一:让函数模板的某个实例成为友元函数 #include <iostream> #include <vector> using namespace std; #pragma warning(disable : 4996) template <typename T> void func(); //声明不可少 class...
  • 友元函数什么是友元函数?友元函数的作用? 什么是友元函数? 类的友元函数可直接访问类中的私有成员变量,该函数是定义在类外的普通函数,不属于任何类,需要在类中加friend关键字声明。 比如我们在重载自定义类型...
  • 友元,是一种突破封装的方式,尽量少用 友元函数 需要友元解决的问题: 运用operator<<进行函数重载,需要输出,若把operator<<定义为成员变量函数,因为cout的输出流对象和隐含的this指针在抢占第一个...
  • 友元函数是一个不属于类成员的函数,但它可以访问该类的私有成员。换句话说,友元函数被视为好像是该类的一个成员。友元函数可以是常规的独立函数,也可以是其他类的成员。实际上,整个类都可以声明为另一个类的友元...
  • 友元函数3. 友元类4. 友元成员函数 1. 前言 友元,一种定义在类外部的普通函数或类,但它需要在类体内进行说明,为了与该类的成员函数加以区别,在说明时前面加以关键字friend。贴一下百度百科的解释百度百科-友元...
  • 一:让类模板的某个实例成为友元。 #include <iostream> #include <vector> #include <list> using namespace std; #pragma warning(disable : 4996) template <typename T> class B; //...
  • //-- 声明类B是类A的友元类,则B可以访问类A的所有成员了。 friend class B; private: //public: int data; }; class B { public: void callBAF(int i, A& a){ a.data = i; std::cout << "a.data...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 51,741
精华内容 20,696
关键字:

友元