我正在尝试理解我通过反复试验设法完成工作的代码段。我理解这个片段的一切,除了为什么当我把“朋友”带出课堂宣言时它不起作用。在这种情况下,我不明白朋友在做什么。
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;
}
答案 0 :(得分:7)
您同时声明并定义了一个使操作符超载的友元函数。
声明为friend
的函数可以访问与其成为联系的类的任何实例的所有私有成员。
这与常规成员函数(显然也可以访问私有成员)不同,因为朋友函数不是类的成员 - 它们是独立函数。
因此,既然您已经在类中定义了独立函数,那么乍看之下就会让人感到困惑 - 只要记住它根本不是一个成员函数。
答案 1 :(得分:3)
这意味着该朋友不是该班级的成员,但您可以无限制地访问static
班级成员和成员类型(包括private
个)。
这使得“外观和感觉”功能成为一个成员。由于operator<<
与logWrapper
密切相关,因此您可以实现它,就好像它是该类的成员一样。
但请记住,它不是会员!它只是一个具有特殊访问权限的免费功能,就像在外面定义一样。
编辑:由于没有静态成员且没有成员类型,因此这不会产生任何影响。你可以在不改变它的情况下将朋友的定义移到外面。不过,这种风格是惯用的,因为你可以。通常它与模板一起使用,模板通常具有成员类型/ typedef。
实际上,在template<…> class
块中定义朋友是定义模板化非模板函数的唯一方法。尽管如此,这种神秘的,有时难以捉摸的野兽有时也非常方便。通常他的创作是偶然的,甚至是偶然的,所以我不会参与讨论......
答案 2 :(得分:3)
除了以前写过的内容之外,查找规则略有不同。如果在befriending类型中声明了friend
函数和,则只会考虑其中一个参数是否属于该特定类型:
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
的大括号内是定义,因此查找将找不到foo
,除非参数(至少一个参数)是类型为B
,这将禁止从A
到B
的隐式转换 - 由于未找到潜在的重载,因此不会执行转换。
这就是为什么在定义模板时最好提供内联的friend
函数(特别是运算符)的实现,因为这会减少函数的范围并减少命名空间污染。
答案 3 :(得分:1)
通常friend
告诉编译器,operator<<
可以访问logWrapper
的私有变量。在您的情况下,它用于直接实现operator<<
内的logWrapper
。也可以像这样实施:
class logWrapper{
}logend;
ostream& operator<<(ostream& os, logWrapper& thislogend){
// ...
}
如果您未使用friend
,则会将operator<<
声明为logWrapper
的成员函数。使用普通函数更容易理解:
class logWrapper{
int func(int i, logWrapper& thislogend){
// ...
}
}logend;
// needs to be called as:
logend.func(5,logend);
// while
class logWrapper{
friend int func(int i, logWrapper& thislogend){
// ...
}
}logend;
// would be called as
func(5,logend);