C++类内定义友元却无需类外声明的特殊情况
将一个全局函数作为某个类的友元时,可以在类内定义函数,但必须在类外对函数进行声明。但有一种特殊情况并不需要再次声明。例如:
#include <iostream>
class Person
{
public:
friend void func1()
{
std::cout << "func1" << std::endl;
}
friend void func2(const Person& p)
{
std::cout << "func2" << std::endl;
}
friend std::ostream& operator<<(std::ostream& os, const Person& p)
{
os << p.age;
return os;
}
friend Person& operator+(Person& p, int a)
{
p.age += a;
return p;
}
private:
int age = 0;
};
int main()
{
Person p;
// func1(); Error
func2(p);
std::cout << p << std::endl;
std::cout << (p + 8) << std::endl;
}
在上述例子中,四个函数都没有在类外进行声明,但只有func1
调用会出错,其他函数调用正常。不难发现,只有func1
函数的形参列表中不包含Person
类。也就是说:
当友元函数定义在类内时,如果函数使用了该类作为参数,则不需要在类外声明
原因也许和模板有关,例如有如下类模板:
#include <iostream>
#include <vector>
template <typename T>
class Stack
{
public:
void push(T value)
{
elems.push_back(value);
}
friend std::ostream& operator<<(std::ostream& os, const Stack<T>& s)
{
s.print();
return os;
}
private:
void print() const
{
for (const T& item : elems)
{
std::cout << item << " ";
}
}
std::vector<T> elems;
};
int main()
{
Stack<int> s;
for (int i = 3; i < 9; ++i)
{
s.push(i);
}
std::cout << s << std::endl;
}
在Stack
类模板里重载了<<
运算符,并作为友元,上述代码表示:Stack
每次实例化的时候,会同时实例化一个operator<<
函数,注意,operator<<
函数并不是函数模板。因此如果想在类外进行声明时,需要对不同Stack
的实例写不同的声明,例如:
// 如果实例化了Stack<int>
std::ostream& operator<<(std::ostream& os, const Stack<int>& s);
// 如果实例化了Stack<double>
std::ostream& operator<<(std::ostream& os, const Stack<double>& s);
...
这样的代码并不generic,原因就是类模板作为参数可以有很多不同的类型,因此,如果友元函数使用了该类作为参数,则不需要在类外声明。