友元函数是指某些虽然不是类成员却能够访问类的所有成员的函数。友元函数在类中声明,在类外定义,使用时不依赖于类或类实例。友元函数的函数可以来自于其他类的成员函数,也可以来自全局函数。
普通类的友元函数
一个简单的友元函数的例子如下:
//t1.h
#include <iostream>
using namespace std;
class My {
private:
int my;
public:
My()=default;
My(int my):my(my) {};
void printm();
friend void printfri();
friend void printfri2(My&);
};
void printfri();//见attention1
void printfri2(My&);//见attention1
//t1.cpp
#include "t1.h"
void printfri() {
cout << "My print friend." << endl;
}
void printfri2(My& m) {
cout << "My print friend2: " << m.my << endl;
}
void My<T>::printm() {
cout << "My print: " << my << endl;
}
//t2.cpp
#include "t1.h"
int main() {
My m(3);
m.printm();
printfri();
printfri2(m);
return 0;
}
/*
*/
模板类的友元函数
对于模板类,情况会稍复杂一些。如果友元函数是非模板函数,则直接按照非模板友元函数的声明定义方法去定义;如果友元函数是模板函数,则可以划分为约束友元函数和非约束友元函数,约束友元函数是指对于类的每一个具体化(每一个模板类)都获得与之匹配的具体化的友元,非约束友元函数是指每个函数模板的具体化都是每个类模板具体化的友元。下面的例子是非约束模板友元函数的例子。
//t1.h
#include <iostream>
using namespace std;
template<class T>
class My {
private:
T my;
public:
My()=default;
My(T my):my(my) {};
void printm();
friend void printfri();
template<class K>
friend void printfri2(My<K>&);
};
void printfri();//见attention1
template <class T> void printfri2(My<T>&);//见attention1
//t1.cpp
#include "t1.h"
void printfri() {
cout << "My print friend." << endl;
}
template<class T>
void printfri2(My<T>& m) {
cout << "My print friend2: " << m.my << endl;
}
template<class T>
void My<T>::printm() {
cout << "My print: " << my << endl;
}
template class My<int>;//显式实例化
template class My<float>;//显式实例化
template void printfri2<int>(My<int>&);//显式实例化
template void printfri2<float>(My<float>&);//显式实例化
//t2.cpp
#include "t1.h"
int main() {
My<int> m(3);
m.printm();
printfri();
printfri2(m);
return 0;
}
/*
*/
需要注意的几点
-
attention1
在类的定义中进行友元的声明仅仅指定了访问的权限,而非一个通常意义上的函数声明。如果我们要调用友元函数,那么我们就必须在友元声明之外再对函数进行一次声明。
为了使友元函数对类的用户可见,我们通常将友元的函数声明与类放在同一个头文件中。
虽然有些编译器并未强制限定友元函数必须在使用之前在类的外部进行声明,但是我们最好这样做,因为如果更换了一个有如此强制要求的编译器我们也无须对代码进行改动。
当类的声明被包含在名称空间块内时,在名称空间内需要声明该友元函数。