友元实例:友元类及友元函数

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

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

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

Test.h:

#ifndef TEST_H
#define TEST_H

#include<iostream>
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 <<endl;
}

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 <iostream>
#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 <iostream>
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" <<endl;
    Test t;
    FriendTest ft;
    t.set(30, 20);
    ft.setTest(t,9,8);
    t.print();
    return 0;
}



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

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

摘自:http://blog.sina.com.cn/s/blog_4901f88e0100hbym.html

第一种写法问题:

编译到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 <string>

#include <Screen.h>

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

 

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值