原文:http://blog.csdn.net/jackychu/article/details/3020866
通常对于普通函数来说,要访问类的保护成员是不可能的,如果想这么做那么必须把类的成员都申明成为public(共用的),然而这么做带来的问题便是任何外部函数都可以毫无约束的访问它操作它,c++利用friend修饰符,可以让一些你设定的函数能够对这些保护数据进行操作,避免把类成员全部设置成public,最大限度的保护数据成员的安全。
友元能够使得普通函数直接访问类的保护数据(private:或protected: ),避免了类成员函数的频繁调用,可以节约处理器开销,提高程序的效率,但矛盾的是,即使是最大限度的保护,同样也破坏了类的封装特性,这即是友元的缺点,在现在cpu速度越来越快的今天我们并不推荐使用它,但它作为c++一个必要的知识点,一个完整的组成部分,我们还是需要讨论一下的。
1.在类里声明一个普通函数,在前面加上friend修饰,那么这个函数就成了该类的友元,可以访问该类的一切成员
下面我们来看一段代码,看看我们是如何利用友元来访问类的一切成员的。
#include <iostream>
using namespace std;
class Internet
{
public:
Internet(char *name,char *address)
{
strcpy(Internet::name,name);
strcpy(Internet::address,address);
}
friend void ShowN(Internet &obj);//友元函数的声明,函数ShowN(Internet &obj不是类Internet的成员函数,而是外部的函数
private: //或protected:
char name[20];
char address[20];
};
void ShowN(Internet &obj)//函数定义,不能写成,void Internet::ShowN(Internet &obj)
{
cout<<obj.name<<endl;
}
void main()
{
Internet a("中国软件开发实验室","www.cndev-lab.com");
ShowN(a);
cin.get();
}
运行结果:
上面的代码通过友元函数的定义,我们成功的访问到了a对象的保护成员name,友元函数并不能看做是类的成员函数,它只是个被声明为类友元的普通函数,所以在类外部函数的定义部分不能够写成void Internet::ShowN(Internet &obj),这一点要注意。
2. 一个普通函数可以是多个类的友元函数
对上面的代码我们进行修改,注意观察变化:
#include <iostream>
using namespace std;
class Country;
class Internet
{
public:
Internet(char *name,char *address)
{
strcpy(Internet::name,name);
strcpy(Internet::address,address);
}
friend void ShowN(Internet &obj,Country &cn);//注意这里,定义了友元函数ShowN
private:
char name[20];
char address[20];
};
class Country
{
public:
Country()
{
strcpy(cname,"中国");
}
friend void ShowN(Internet &obj,Country &cn);//注意这里,也定义了友元函数ShowN
protected:
char cname[30];
};
void ShowN(Internet &obj,Country &cn) //函数的参数分别来自两个不同的类的对象
{
cout<<cn.cname<<"|"<<obj.name<<endl;
}
void main()
{
Internet a("中国软件开发实验室","www.cndev-lab.com");
Country b;
ShowN(a,b);
cin.get();
}
运行结果:
3一个类的成员函数函数也可以是另一个类的友元,从而可以使得一个类的成员函数可以操作另一个类的数据成员
我们在下面的代码中增加一类Country,注意观察:
#include <iostream>
using namespace std;
class Internet;
class Country
{
public:
Country()
{
strcpy(cname,"中国");
}
void Editurl(Internet &temp);//成员函数的声明
protected:
char cname[30];
};
class Internet
{
public:
Internet(char *name,char *address)
{
strcpy(Internet::name,name); //类或命名空间引用其下的采用是用::,对象引用其成员时用.
strcpy(Internet::address,address);
}
friend void Country::Editurl(Internet &temp);//把Country类中的Editurl函数申明为Internet类的友元函数
protected:
char name[20];
char address[20];
};
void Country::Editurl(Internet &temp)//在类的外部定义成员函数,注意定义形式:返回值 类名::函数名(参数表)
{
strcpy(temp.address,"change address by a friend fuction of another class");
cout<<temp.name<<"|"<<temp.address<<endl;
}
void main()
{
Internet a("中国软件开发实验室","www.cndev-lab.com");
Country b;
b.Editurl(a);
cin.get();
}
运行结果:
4.整个类也可以是另一个类的友元,该友元也可以称做为友类。友类的每个成员函数都可以访问另一个类的所有成员。
示例代码如下:
#include <iostream>
using namespace std;
class Internet;
class Country
{
public:
Country()
{
strcpy(cname,"中国");
}
friend class Internet;//将Internet类申明为Country的友类
protected:
char cname[30];
};
class Internet
{
public:
Internet(char *name,char *address)
{
strcpy(Internet::name,name);
strcpy(Internet::address,address);
}
void Editcname(Country &temp);
protected:
char name[20];
char address[20];
};
void Internet::Editcname(Country &temp) //定义Internet类的成员函数
{
strcpy(temp.cname,"保护成员被友类中的函数更改");
cout<<temp.cname;
}
void main()
{
Internet a("中国软件开发实验室","www.cndev-lab.com");
Country b;
a.Editcname(b);
cin.get();
}
在上面的代码中我们成功的通过Internet类Editcname成员函数操作了Country类的保护成员cname。
运行结果:
5.使用友元类时应注意:
友元关系不能被继承
友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。
友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明
在编程中,我们使用友元的另外一个重要原因是为了方便重载操作符的使用,这些内容我们将在后面的教程着重讨论!