下面都说了,如果你不需要运营商成为朋友,那就不要把它变成朋友。特别是对于输出操作符,在我看来你不应该让他们成为朋友。这是因为如果您的类可以输出到流,它应该具有等效的get 函数,以编程方式提供相同的数据。在这种情况下,您可以根据 get 函数将 operator<< 写成非朋友。
如果你有充分的理由让他们成为朋友,你可以做一个朋友定义
template <class A> class MyClass {
public:
friend ostream & operator<<(ostream & os, MyClass<A> const& mc) {
// ...
}
};
这样您就不需要获得A 类型的template<...> 子句。如果您在模板中定义运算符,则已经知道。请注意,即使您在模板中定义了它,它也不是成员函数。它仍然是非成员,但可以访问类中声明的名称(如模板参数)。对于您创建的每个 MyClass 实例,都会从打印内容的友元函数创建一个不同的 非模板 运算符函数。
如果你想在外面定义模板,你必须预先声明它才能将它的给定特化声明为友元。
// predeclare it so you can make it a friend.
template <class A> class MyClass;
template <class A> ostream &operator<<(ostream &os, MyClass<A> const&);
template <class A> class MyClass{
public:
/* the "<A>" is needed - it says that a given instantiation of
that template is a friend, and not a non-template function. */
friend ostream & operator<< <A>(ostream & os, MyClass<A> const& mc);
};
template <class A>
ostream & operator<<(ostream & os, MyClass<A> const& mc){
// some code
return os;
}
这使operator<< <Foo> 成为MyClass<Foo> 的朋友。如果您要省略 <A> 或也可能为空的 <>,编译器会理解为说您创建了一个 non-template 运算符,该运算符具有具体参数而不是模板参数。 p>
更简单但不太“正确”的解决方案是让MyClass <Foo> 将所有operator << 实例化为朋友。所以理论上operator << <Bar> 可以访问MyClass <Foo> 的私有成员。这不是想要的,但它也有效,获得了比需要更多的访问权限。它消除了前向声明的需要:
template <class A> class MyClass{
public:
/* make all instantiations friends. */
template<typename T>
friend ostream & operator<<(ostream & os, MyClass<T> const& mc);
};
template <class T>
ostream & operator<<(ostream & os, MyClass<T> const& mc){
// some code
return os;
}