我正在尝试理解一段代码片段,这段代码片段是我通过反复试验成功的。我理解这段代码的所有内容,除了当我将"friend“从类声明中去掉时,它为什么不起作用。我不明白在这种情况下朋友在做什么。
stringstream log;
class logWrapper {
friend ostream& operator<<(ostream& os, logWrapper& thislogend)
{
stringstream &ss = dynamic_cast(os);
// This line replaced with printf for clarity
// The actual code sends the C style string to a
// legacy logging system that only takes C style strings
// _log(LOG_ERR, "%s", ss.str().c_str());
printf("%s\n", ss.str().c_str());
ss.str("");
return os;
}
} logend;
int main(void)
{
log << "This is a test" << logend;
}发布于 2011-04-05 06:46:53
同时声明和定义一个友元函数,该函数重载了一个运算符。
声明为friend的函数可以访问与它们成为好友的类的任何实例的所有私有成员。
这与常规成员函数(显然也可以访问私有成员)不同,因为友元函数不是类的成员--它们是独立的函数。
因此,由于您已经在类中定义了独立函数,所以乍一看它似乎很混乱--只需记住它根本不是一个真正的成员函数。
发布于 2011-04-05 06:40:53
这意味着该朋友不是类的成员,但您可以访问static类成员和成员类型(包括private成员),而无需限定。
这使得函数“看起来和感觉”像是一个成员。因为这里的operator<<与logWrapper紧密相关,所以您可以直观地将其作为类的成员进行实现。
但请记住,它不是成员!它只是一个具有特殊访问权限的自由函数,就好像它是在外部定义的。
编辑:由于没有静态成员,也没有成员类型,这在这里不会有什么区别。您可以将好友的定义移到外部,而不更改它。但是,这种风格是惯用的,因为您可以。它通常与模板一起使用,模板通常有成员类型/typedefs。
实际上,在template<…> class块中定义友元是定义模板化非模板函数的唯一方法。尽管如此,这种深奥而有时难以捉摸的野兽有时还是非常方便的。通常他的创作是偶然的,甚至是偶然的,所以我不会深入讨论…
发布于 2011-04-05 16:09:17
除了之前编写的内容之外,查找规则略有不同。如果friend函数是在befriending中声明和定义的,那么只有当其中一个参数属于该特定类型时,才会考虑该函数:
struct A {};
struct B {
B() {} // allow default construction
B( A const & ) {} // and implicit conversion from A
friend void foo( B const & ) // defined in the class
{}
friend void bar( B const & );
};
void bar( B const & ) {} // defined outside
int main() {
A a;
bar( a ); // ok, implicit conversion and calls bar(B(a))
//foo( a ); // error: foo not in scope!!! [*]
B b;
foo( b ); // ok: the argument makes the compiler look inside B
foo( B(a) ); // same here
}*由于foo是在B的大括号内定义的,因此除非参数(至少有一个参数)是B类型,否则查找将找不到foo,这将禁止从A到B的隐式转换--由于没有发现潜在的重载,因此不会执行转换。
这就是为什么在定义模板时,最好以内联方式提供friend函数(特别是运算符)的实现的原因之一,因为这样可以减少函数的范围并减少名称空间污染。
https://stackoverflow.com/questions/5545112
复制相似问题