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

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

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

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

Test.h:

  1. #ifndef TEST_H  
  2. #define TEST_H  
  3.   
  4. #include<iostream>  
  5. using namespace std;  
  6.   
  7. class Test  
  8. {  
  9.     friend class FriendTest;    //此处声明FriendTest为Test的友元类,FriendTest类可以访问Test的私有成员  
  10.     public:  
  11.         Test();  
  12.         void set(int h,int w);  
  13.         void print();  
  14.         virtual ~Test();  
  15.     protected:  
  16.     private:  
  17.         int height;  
  18.         int weight;  
  19. };  
  20.   
  21. #endif // TEST_H  

Test.cpp

  1. #include "../include/Test.h"  
  2.   
  3. Test::Test()  
  4. {  
  5.     //ctor  
  6.     height = 0;  
  7.     weight = 0;  
  8. }  
  9. void Test::set(int h, int w)  
  10. {  
  11.     height = h;  
  12.     weight = w;  
  13. }  
  14. void Test::print()  
  15. {  
  16.     cout << height << "  ";  
  17.     cout << weight <<endl;  
  18. }  
  19.   
  20. Test::~Test()  
  21. {  
  22.     //dtor  
  23. }  

下面关于FriendTest的相关程序。

FriendTest.h

  1. #ifndef FRIENDTEST_H  
  2. #define FRIENDTEST_H  
  3.   
  4. #include "Test.h"  
  5.   
  6. class FriendTest  
  7. {  
  8.     public:  
  9.         FriendTest();  
  10.         void setTest(Test& t, int h, int w);      
  11.         virtual ~FriendTest();  
  12.     protected:  
  13.     private:  
  14. };  
  15.   
  16. #endif // FRIENDTEST_H  

FriendTest.cpp

  1. #include "../include/FriendTest.h"  
  2.   
  3. FriendTest::FriendTest()  
  4. {  
  5.     //ctor  
  6. }  
  7. void FriendTest::setTest(Test& t, int h, int w)     //之前声明了友元,所以此处可以调用私有成员  
  8. {  
  9.    t.height = h;  
  10.    t.weight = w;  
  11. }  
  12. FriendTest::~FriendTest()  
  13. {  
  14.     //dtor  
  15. }  
  1. #include <iostream>  
  2. #include "./include/Test.h"  
  3. #include "./include/FriendTest.h"  
  4.   
  5. using namespace std;  
  6.   
  7. int main()  
  8. {  
  9.     Test t;  
  10.     FriendTest ft;  
  11.     t.set(30, 20);  
  12.     ft.setTest(t,9,8);  
  13.     t.print();  
  14.     return 0;  
  15. }  

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

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

  1. #include <iostream>  
  2. using namespace std;  
  3. //由于两个类都使用到了另一个类,所以顺序很关键。如果将两个类的顺序颠倒会出现编译不通过,并提示未定义。另外友元函数必须在最后实现,因为它用到了两个类中的成员。仔细与上一部分的代码比较,你便会了解里边的玄机。。。  
  4. class Test;      //首先需要声明Test类,FriendTest类中需要使用。  
  5. class FriendTest  
  6. {  
  7.     public:  
  8.         FriendTest();  
  9.         void setTest(Test& t, int h, int w);  
  10.         virtual ~FriendTest();  
  11.     protected:  
  12.     private:  
  13. };  
  14. class Test  
  15. {  
  16.     friend void FriendTest::setTest(Test& t, int h, int w);     //友元函数声明  
  17.     public:  
  18.         Test();  
  19.         void set(int h,int w);  
  20.         void print();  
  21.         virtual ~Test();  
  22.     protected:  
  23.     private:  
  24.         int height;  
  25.         int weight;  
  26. };  
  27.   
  28. void FriendTest::setTest(Test& t, int h, int w)  
  29. {  
  30.    t.height = h;  
  31.    t.weight = w;  
  32. }  
  33.   
  34. int main()  
  35. {  
  36.     cout << "friend" <<endl;  
  37.     Test t;  
  38.     FriendTest ft;  
  39.     t.set(30, 20);  
  40.     ft.setTest(t,9,8);  
  41.     t.print();  
  42.     return 0;  
  43. }  



 另外在网上看到了一个关于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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值