友元是一种定义在类外部的普通函数或类,但它需要在类体内进行说明,为了与该类的成员函数加以区别,在说明时前面加以关键字friend。友元不是成员函数,但是它可以访问类中的私有成员。(百度百科)
一、友元函数
如果某函数是某个类的友元函数,则可以在该函数中访问到该类的所有成员。
例:func()是类A的友元函数,则在func()中可以访问到类A的所有成员(包括私有成员和保护成员)。
/*code block 1*/
class A {
friend int getAInfo(A a);
friend int getAValue(A a);
friend void doAShow(A a);
private:
int info;
void show() {
cout << "info: " << info << ", value: " << value << endl;
}
protected:
int value;
public:
A(int _info, int _value) : info(_info), value(_value) {
}
~A() {
}
};
//访问了类A的私有成员info
int getAInfo(A a) {
return a.info;
}
//访问了类A的保护成员value
int getAValue(A a) {
return a.value;
}
//调用了类A的私有成员函数show()
void doAShow(A a) {
a.show();
}
int main() {
A a1(45, 13);
A a2(23, 3);
cout << getAInfo(a1) << endl;
cout << getAInfo(a2) << endl;
cout << "-------------------" << endl;
cout << getAValue(a1) << endl;
cout << getAValue(a2) << endl;
cout << "-------------------" << endl;
doAShow(a1);
doAShow(a2);
return 0;
}
代码块1的运行结果如下:
上面说到了所有成员,那么静态成员呢?试试吧。
/*code block 2*/
class A {
friend int getStaticMember();
friend void doStaticFunction();
private:
static int objectCount;
static void show() {
cout << "A::show()" << endl;
}
public:
A() {
++objectCount;
}
~A() {
}
};
int A::objectCount = 0;
//访问了类A的静态私有成员objectCount
int getStaticMember() {
return A::objectCount;
}
//调用了类A的静态私有成员函数show()
void doStaticFunction() {
A::show();
}
int main() {
A a1;
cout << "objectCount: " << getStaticMember() << endl;
doStaticFunction();
A a2;
cout << "objectCount: " << getStaticMember() << endl;
doStaticFunction();
A a3;
cout << "objectCount: " << getStaticMember() << endl;
doStaticFunction();
return 0;
}
代码块2的运行结果如下:
代码块1和2证明了类的友元函数可以访问类的所有成员。
二、友元类
若类A是类B的友元类,则类B中所有的成员都能在类A中访问到,称“类A中的所有成员都为类B的友元函数”(搞清楚这个关系)。简单来说就是,你是我的朋友,那么我的很多东西你都可以使用(C++里这种朋友更加无私,可以分享一切供朋友使用)。
看看下面的例子:
/*code block 3*/
class A {
friend class B;
private:
int info;
static int objectCount;
protected:
int value;
public:
A(int _info, int _value) : info(_info), value(_value) {
++objectCount;
}
~A() {
}
};
int A::objectCount = 0;
class B {
public:
//访问了类A的私有成员info
void showAInfo(A a) {
cout << "info: " << a.info << endl;
}
//访问了类A的保护成员info
void showAValue(A a) {
cout << "value: " << a.value << endl;
}
//访问了类A的静态私有成员objectCount
void showAObjectCount() {
cout << "objectCount: " << A::objectCount << endl;
}
};
int main() {
B b;
A a1(13, 98);
b.showAInfo(a1);
b.showAValue(a1);
b.showAObjectCount();
A a2(4, 65);
b.showAInfo(a2);
b.showAValue(a2);
b.showAObjectCount();
return 0;
}
代码块3的运行结果如下:
这里要注意:就像那句话说的“我把你当兄弟,你却把我当父亲”,C++中类的友元关系也是单向的,不具有交换性。如果类A是类B的友元类,那么类A的所有成员函数都是类B的友元函数,反之不然。
下面,给出一个错误示例:
/*code blocks 4*/
class A {
friend class B;
private:
int info;
protected:
int value;
public:
A(int _info, int _value) : info(_info), value(_value) {
}
~A() {
}
//访问类B的私有成员info和保护成员value
void visitBMembers(B b) {
cout << "B::info: " << b.info << ", B::value: " << b.value << endl;
}
};
class B {
public:
B(int _info, int _value) : info(_info), value(_value) {
}
~B() {
}
//访问类A的私有成员info和保护成员value
void visitAMembers(A a) {
cout << "A::info: " << a.info << ", A::value: " << a.value << endl;
}
private:
int info;
protected:
int value;
};
编译出错,报错内容如下:
上图中说“B has not been declared”,错误位置是在void A::visitBMembers(int)中,说明在类A中不能访问类B的私有成员和保护成员。也印证了上文中的说法,友元类的关系是单向的,不具有交换性。
那么,友元关系能不能够传递呢?再试试。(C是B的朋友,B是A的朋友,那C和A是什么关系)
/*code block 5*/
class A {
friend class B;
private:
int info;
public:
A(int _info) : info(_info) {
}
~A() {
}
};
class B {
friend class C;
private:
int info;
public:
B(int _info) : info(_info) {
}
~B() {
}
//访问类A的私有成员info
void visitAInfo(A a) {
cout << "A::info: " << a.info << endl;
}
};
class C {
public:
//访问类B的私有成员info
void visitBInfo(B b) {
cout << "B::info: " << b.info << endl;
}
};
int main() {
A a(23);
B b(34);
C c;
c.visitBInfo(b);
b.visitAInfo(a);
return 0;
}
代码块5的运行结果如下:
将代码块5的代码稍作修改如下(类A和类B的代码以及主函数不变):
/*code block 6*/
class C {
public:
//访问类B的私有成员info
void visitBInfo(B b) {
cout << "B::info: " << b.info << endl;
}
//访问类A的私有成员info
void visitAInfo(A a) {
cout << "A::info: " << a.info << endl;
}
};
编译出错,报错内容如下:
说明类C不能直接访问类A的私有成员和保护成员,因此类C不是类A的友元类,即友元关系不具有传递性。
接下来,验证一下友元关系是否能继承。
/*code blocks 7*/
class A {
friend class B;
private:
int info;
public:
A(int _info) : info(_info) {
}
~A() {
}
};
class B {
public:
//访问A的私有成员info
void BVisitAInfo(A a) {
cout << "BVisitAInfo():A::info: " << a.info << endl;
}
};
class C : public B {
public:
//访问A的私有成员info
void CVisitAInfo(A a) {
cout << "CVisitAInfo():A::info: " << a.info << endl;
}
};
编译出错,报错内容如下:
代码块7中,类B是类A的友元类,类C是类B的派生类。但从报错内容中可以看出,类A的私有成员info对类C是不可见的,所以友元关系也不能被继承。
三、类的成员函数作为另一个类的友元函数
若类A的某个成员函数是类B的友元函数,则可以通过该成员函数访问到类B的所有成员。
若类A是类B的友元类,则可以通过类A的所有成员函数访问到类B的所有成员。
这两者的差别其实就在于“所有”这两个字,友元类的开放范围更大,而成员函数作为另一个类的友元函数,开放的入口只有一个函数。
/*code blocks 8*/
//类B的前向声明
class B;
class A {
public:
void visitBInfo(B b);
};
class B {
friend void A::visitBInfo(B b);
private:
int info;
public:
B(int _info) : info(_info) {
}
~B() {
}
};
//访问类B的私有成员info
void A::visitBInfo(B b) {
cout << "B::info: " << b.info << endl;
}
int main() {
B b(87);
A a;
a.visitBInfo(b);
return 0;
}
代码块8的运行结果如下:
/*code blocks 9*/
class B;
class A {
public:
void visitBInfo(B b);
void visitBInfoWithOutFriend(B b);
};
class B {
friend void A::visitBInfo(B b);
private:
int info;
public:
B(int _info) : info(_info) {
}
~B() {
}
};
//访问B的私有成员info
void A::visitBInfo(B b) {
cout << "B::info: " << b.info << endl;
}
//访问B的私有成员info
void A::visitBInfoWithOutFriend(B b) {
cout << "B::info: " << b.info << endl;
}
编译出错,报错内容如下:
通过报错内容可以看到,未将void A::visitBInfoWithOutFriend(B)声明为类B的友元函数,是无法通过该函数访问到类B的私有成员和保护成员的。
基本上,到这里,关系就清楚了。
总结几点:
1、友元关系不具有交换性。
2、友元关系不具有传递性。
3、友元关系不可被继承。
4、若将类A作为类B的友元类,则类A中的所有成员函数都是类B的友元函数。
5、在某类外,只能通过被声明为该类的友元函数的函数访问该类的私有成员和保护成员。
大概,就这么多吧。欢迎补充。