当你声明一个朋友然后在一个类中定义它时,这意味着什么?

时间:2011-04-04 22:37:21

标签: c++

我正在尝试理解我通过反复试验设法完成工作的代码段。我理解这个片段的一切,除了为什么当我把“朋友”带出课堂宣言时它不起作用。在这种情况下,我不明白朋友在做什么。


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; }

4 个答案:

答案 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
}

[*]由于fooB的大括号内是定义,因此查找将找不到foo,除非参数(至少一个参数)是类型为B,这将禁止从AB的隐式转换 - 由于未找到潜在的重载,因此不会执行转换。

这就是为什么在定义模板时最好提供内联的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);