1、友元函数
为什么会有友元函数?
结合着类的特性和类中一般成员函数,我们可以这样理解:类具有封装和信息隐藏的特性。只有类的成员函数才能访问类的私有成员,程序中的其他函数是无法访问私有成员的。非成员函数可以访问类中的公有成员,但是如果将数据成员都定义为公有的,这又破坏了隐藏的特性。另外,应该看到在某些情况下,特别是在对某些成员函数多次调用时,由于参数传递,类型检查和安全性检查等都需要时间开销,而影响程序的运行效率。
为了解决上述问题,提出一种使用友元的方案。友元是一种定义在类外部的普通函数,但它需要在类体内进行说明,为了与该类的成员函数加以区别,在说明时前面加以关键字friend。友元不是成员函数,但是它可以访问类中的私有成员。友元的作用在于提高程序的运行效率,但是,它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。
友元函数的特点是能够访问类中的私有成员的非成员函数。友元函数从语法上看,它与普通函数一样,即在定义上和调用上与普通函数一样。
友元函数的使用
例如:cb.cpp需要访问ca.h的私有变量
ca.h
#pragma once
#include <iostream>
#include <string>
using namespace std;
class cb;
class ca {
private:
string id;
void setId(string s) {
id = s;
}
protected:
string name;
void setName(string s) {
name = s;
}
public:
void print() {
cout << id << " " << name << " " << endl;
}
friend void test(ca& a); //申明cb类的test()函数作友元,允许它访问私有保护成员
};
cb.cpp
#include"ca.h"
using namespace std;
class ca; //事先申明ca类,确保cb类的定义不出错
class cb { //在ca类之前定义cb类,确保在ca类里申明cb的test()作友元时不出错
public:
friend void test(ca& a); //由于ca类事先申明,这儿不出错
};
void test(ca& a) { //作友元的成员函数的实装必须在ca类的后面,否则ca类的成员就未定义了。
a.id = "123"; //这是ca类的私有成员
a.setName("abc"); //这是ca类的保护成员
}
int main ( )
{
ca a;
cb b;
test(a);
a.print();
return ;
}
运行结果:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICdzFWRoRXdvN1LclHdpZXYyd2LcBzNvwVZ2x2bzNXak9CX90TQNNkRrFlQKBTSvwFbslmZvwFMwQzLcVmepNHdu9mZvwFVywUNMZTY18CX052bm9CX90TUZlmVYFGeKhlWwZlMkZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39zN2UjM0czMyIDNwQDM3EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
2、友元类
当一个类作为另一个类的友元时,这就意味着这个类的所有成员函数都是另一个类的友元函数。
ca.h:
#pragma once
#include <iostream>
#include <string>
using namespace std;
class ca {
public:
ca() : mX(), mY() {}
friend class cb;
private:
void PrintData() const
{
cout << "mX = " << mX << endl
<< "mY = " << mY << endl;
}
int mX;
int mY;
};
cb.cpp:
#include <iostream>
#include <string>
#include"ca.h"
using namespace std;
//class ca; //事先申明ca类,确保cb类的定义不出错
class cb { //在ca类之前定义cb类,确保在ca类里申明cb的test()作友元时不出错
private:
ca mObj;
public:
cb(int x, int y)
{
mObj.mX = x; //直接调用类CObj的私有数据成员
mObj.mY = y;
}
void ShowData() const
{
mObj.PrintData(); //直接调用类CObj的私有成员函数
}
};
int main ( )
{
cb one(, );
one.ShowData();
return ;
return ;
}
使用友元类时注意:
() 友元关系不能被继承。
() 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。
() 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明
总结起来:
()友元关系不可以继承,但对已有的方法来说访问权限不改变。
()如果改写基类的方法则访问权限改变
()友元关系不具有传递性
若类B是类A的友元,类C是B的友元,类C不一定是类A的友元。