学习了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