友元
友元 英文 friend。friend 翻译成中文就是朋友,翻译成术语就是:友元。朋友就很好理解了,我的钱你随便花,我的东西你随便用;当然我也是你的朋友,你的钱我随便花,你的东西我随便用。
当然在 C++ 里,类与类 之间可以作为友元,那么这个类就可以去操作另外一个类里面私有的成员;函数与函数 之间也可以作为 友元,所以友元分为: 友元函数 和 友元类。
我们通过一个例子一看就明白了:
写代码
#include <iostream>
#include <string>
using namespace std;
class Screen{
public:
typedef std::string::size_type index;
Screen(int ht=0, int wd=0):contents(ht*wd, ' '), cursor(0), height(ht), width(wd){}
int area() const{
return height * width;
}
private:
std::string contents;
index cursor;
int height, width;
};
int main(){
Screen a;
cout << a.area() << endl;
cout << "OK" << endl;
return 0;
}
运行现在的程序,程序是可以正常使用的。
现在,我们在main()
函数的同一级,编写一个函数,这个函数的功能是:计算屏幕(Screen)的面积。
// 这个函数不是类的成员函数
int calcArea(Screen & screen){
return screen.height * screen.width;
}
如果这个函数像上面这个样子编写,程序编译都通不过。因为 height
和 width
都是 Screen
类的私有成员。这两个私有的数据成员只能在类的内部使用,只能被类的内部函数使用,因为这个calcArea()
函数不是类内部的成员函数,所以它是不能使用类内部的私有成员的。
那么,假如现在,我们把这个 calcArea()
函数变成这个 Screen
类的友元,就是朋友,那么这个函数就可以使用类里面私有的成员了。就像是:你是我的朋友,到我家里来,就像到自己家里一样,随便吃随便用随便拿。
现在我们就来定义友元函数。我们将calcArea()
函数定义成友元函数。
在 Screen
类里面,public
里面添加下面这句代码就可以。就这么简单:
friend int calcArea(Screen & screen);
现在,我们在编译程序,就没有错误了。运行也没有问题。main()
函数里面写成下面这个样子,来测试:
int main(){
Screen a;
cout << a.area() << endl;
cout << calcArea(a) << endl;
cout << "OK" << endl;
while(1){}
return 0;
}
我们也可以将一个类编写成友元,我们现在来看下面这个例子:(注意: 要将下面的这段代码放到Screen
类的下面,否则Window_Mgr
类找不到 Screen
类。)
// 窗口管理类 - 对Screen类进行管理
class Window_Mgr{
public:
// 重定位 - 就是改变窗口的height 和 width
void relocate(int r, int c, Screen& s){
s.height += r;
s.width + c;
}
};
因为 Screen
类里的 height
和 width
是私有的,不能再 Window_Mgr
类里面使用的,除非它是友元。
现在编译程序是报错的。
我们现在可以将Window_Mgr
类作为Screen
类的友元。需要做的事情,只需要:在Screen
类里面的public
里面添加下面一句代码:
friend class Window_Mgr;
现在,我们将Window_Mgr
这个整个类都作为 Screen
类的友元,也就是说:它们现在是朋友,我们家里的人可以随便到你们家里面来,你们家里的人也可以随便到我们家里面来。
我们在 main()
函数里面测试一下:
int main(){
Screen a(60, 100);
cout << a.area() << endl;
Window_Mgr w;
w.relocate(10, 20, a);
cout << calcArea(a) << endl;
cout << "OK" << endl;
while(1){}
return 0;
}
这就是友元,懂了吗?
如果我们现在不行让这个 Window_Mgr
类作为 Screen
类的友元,而是希望只是 Window_Mgr
类中的一个成员函数是Screen
类的友元。要如何操作呢?
我们在定义一个类,Dog
。Dog
类里面就有很多的成员函数。
我现在不想将Dog
类全部做成Screen
类的友元,我只想将Dog
类里面的foo()
共有函数作为Screen
类的友元,那现在我们要如何去做呢?
很简单,我们在Screen
类的public
里面添加下面这句代码就可以:
friend int Dog::foo(Screen & );
Q: 现在程序编译时会通过的,这是为什么?
A: 有一个问题需要强调一下:友元定义 和 友元声明 之间有一个依赖。
如果我们将 Dog
类 放在 Screen
类的下面,那么 Dog
类是可以找到 Screen
类,但是 Screen
类却找不到 Dog
类里面的foo()
函数,因为我们在编写 foo()
函数的时候,是使用的声明和定义一体的形式编写的。
如果我们将 Dog
类 放在 Screen
类的上面, 那么 Screen
类是可以找到 Dog
类里面的 foo()
函数,但是 Dog
类现在又找不到 Screen
类了。所以,不管你将 Dog
类放在程序的什么位置,程序都是没有办法编译通过。要怎样解决这个问题呢?
我们需要在 Screen
类上面 这样写:
class Screen;
class Dog{
public:
int foo(Screen & screen);
int koo(Screen & screen){
return 1;
}
};
先对 Screen
类进行声明,接下定义 Dog
类。并且在 Dog
类里面 我们将 foo()
函数写成声明的形式。这样就没有使用到 Screen
类里面的成员,这样,程序在编译这段代码的时候不需要去找 Screen
的定义。
接着,我们在 Screen
类的下面 这样写:
int Dog::foo(Screen & screen){
return screen.height * screen.width;
}
我们在 Screen
类的下面都 Dog
类里面的成员函数 foo()
函数进行定义。这样做的原因是:因为 foo()
成员函数里面使用到了 Screen
类里面定义的成员变量,程序在编译这段函数的代码的时候,会去上向上找 Screen
类的定义,刚好我们将 foo()
函数的定义写在Screen
定义的下面,所以这样写就可以用个编译。
现在在main()
函数中写一些测试代码:
int main(){
Screen a(60, 100);
cout << a.area() << endl;
Dog d;
cout << d.foo(a) << endl;
cout << "OK" << endl;
while(1){}
return 0;
}
现在 友元 我们就都介绍完毕了。
最后,完整的代码贴上:
#include <iostream>
#include <string>
using namespace std;
class Screen;
class Dog{
public:
int foo(Screen & screen);
int koo(Screen & screen){
return 1;
}
};
class Screen{
public:
friend int calcArea(Screen & screen);
friend class Window_Mgr;
friend int Dog::foo(Screen & screen);
typedef std::string::size_type index;
Screen(int ht=0, int wd=0):contents(ht*wd, ' '),
cursor(0), height(ht), width(wd){}
int area() const{
return height * width;
}
private:
std::string contents;
index cursor;
int height, width;
};
// 窗口管理类 - 对Screen类进行管理
class Window_Mgr{
public:
// 重定位 - 就是改变窗口的height 和 width
void relocate(int r, int c, Screen& s){
s.height += r;
s.width += c;
}
};
int Dog::foo(Screen & screen){
return screen.height * screen.width;
}
// 这个函数不是类的成员函数
int calcArea(Screen & screen){
return screen.height * screen.width;
}
int main(){
Screen a(60, 100);
cout << a.area() << endl;
Window_Mgr w;
w.relocate(10, 20, a);
cout << calcArea(a) << endl;
Dog d;
cout << d.foo(a) << endl;
cout << "OK" << endl;
while(1){}
return 0;
}
总结:
1 . 今天我们学习的就是友元,友元就是找朋友。我们可以将一个函数作为友元,我们也可以将一个类作为友元,也可以将类中的一个成员函数作为友元。
2 . 所有友元函数有两种: 普通函数 和 类的成员函数(共有 和 私有都可以。)
3 . 友元,道理上是很简单的。友元了之后,就可以操作所有私有的数据成员和私有函数。