友元实例:友元类及友元函数
学习了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
{
}
class Window_Mgr
{
public:
}
第二种写法问题在于:
编译到relocate时,由于Screen& s的实现使用到Screen的成员变量,虽然前面给出了Screen的声明,但此时还不清楚Screen的完整定义,所以编译出错。
class
class Window_Mgr
{
public:
}
class Screen
{
}
第三种写法:
将Window_Mgr::relocate的实现移动到最后,由于编译类Window_Mgr时,并不需要Screen&s 的实现细节,问题得到解决
class
class Window_Mgr
{
public:
}
class Screen
{
}
可见,这两个类如果编译成功需要严格的交替顺序
这也就解释了为什么放在两个文件中无法编译。
附录:
一开始的实现的不能编译的两个文件
实现分别如下:Window_Mgr.h
#ifndef WINDOW_MGR //为了避免两个文件嵌套
#define WINDOW_MGR
#include <string>
#include <Screen.h>
class Window_Mgr
{
public:
}
#endif
Screen.h
#ifndef SCREEN
#define SCREEN
#include "Window_Mgr.h"
class Screen
{
}
#endif