简体   繁体   English

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

[英]What does it mean when you declare a friend and then define it inside a class?

I'm trying to understand a code snippet that I've managed to make work by trial and error. 我正在尝试理解我设法通过反复试验来完成工作的代码段。 I understand everything about this snippet except why it doesn't work when I take "friend" out of the class declaration. 我理解这个片段的一切,除了为什么当我把“朋友”带出课堂宣言时它不起作用。 I don't understand what friend is doing in this context. 在这种情况下,我不明白朋友在做什么。


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

You are simultaneously declaring and defining a friend function, which overloads an operator. 您同时声明并定义了一个使运算符重载的友元函数。

Functions which are declared as friend can access all the private members of any instance of the class which befriended them. 声明为friend函数可以访问与它们成为友好的类的任何实例的所有私有成员。

This is different from regular member functions (which can obviously also access private members), since friend functions are not members of the class -- they are stand-alone functions. 这与常规成员函数(显然也可以访问私有成员)不同,因为友元函数不是类的成员 - 它们是独立的函数。

So since you've defined the stand-alone function inside the class, it appears confusing at first glance -- just remember that it's not really a member function at all. 所以,既然你已经定义的类的独立功能,乍看之下令人困惑-只记得它不是一个真正的成员函数都没有。

It means that the friend is not a member of the class, but you can access static class members and member types (including private ones) without qualification. 这意味着该朋友不是该类的成员,但您可以无限制地访问static类成员和成员类型(包括private类)。

This makes the function "look and feel" like a member. 这使得“外观和感觉”功能成为一个成员。 Because operator<< here is intimately tied to the logWrapper , it is intuitive that you can implement it as if it were a member of the class. 因为operator<<这里与logWrapper密切相关,所以你可以直观地实现它,就像它是的成员一样

But remember, it is not a member! 但请记住,它不是会员! It is just a free function with special access privileges, just as if it were defined outside. 它只是一个具有特殊访问权限的免费功能,就像在外部定义一样。

Edit: Since there are no static members and no member types, this happens not to make a difference here. 编辑:由于没有静态成员且没有成员类型,因此这不会产生任何影响。 You could move the definition of the friend outside without changing it. 你可以在不改变它的情况下将朋友的定义移到外面。 This style is idiomatic, though, because you could. 不过,这种风格是惯用的,因为你可以。 Often it is used with templates, which often do have member types/typedefs. 它通常与模板一起使用,模板通常具有成员类型/ typedef。

Indeed, defining a friend inside a template<…> class block is the only way to define a templated non-template function . 实际上,在template<…> class块中定义朋友是定义模板化非模板函数的唯一方法。 This esoteric and sometimes-elusive beast is nonetheless sometimes very convenient to have around. 尽管如此,这种神秘的,有时难以捉摸的野兽有时也非常方便。 Usually his creation is accidental, even serendipitous, so I won't get into that discussion… 通常他的创作是偶然的,甚至是偶然的,所以我不会参与讨论......

Besides what has been written before, the lookup rules are slightly different. 除了以前写过的内容之外,查找规则略有不同。 If the friend function is declared and defined inside the befriending type, then it will only be considered if one of the arguments is of that particular type: 如果在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
}

[*] Since foo is defined inside B 's braces, lookup will not find foo unless the argument (at least one argument) is of type B , and that will inhibit the implicit conversion from A to B --since the potential overload is not found, conversion is not performed. [*]因为foo是在B的括号内定义的,所以查找将找不到foo除非参数(至少一个参数)是B ,并且这将禁止从AB的隐式转换A因为潜在的重载是未找到,不执行转换。

This is one of the reasons why, when defining a template, it is better to provide the implementation of the friend functions (specially operators) inline, as that reduces the scope of the functions and reduces namespace pollution. 这就是为什么在定义模板时,最好是内联地提供friend函数(特别是运算符)的实现,因为这会减少函数的范围并减少命名空间污染。

Normally friend just tells the compiler, that the operator<< has access to the private variables of logWrapper . 通常friend告诉编译器, operator<<可以访问logWrapper的私有变量。 In your case it's used to directly implement the operator<< inside the logWrapper . 在你的情况下,它用于在logWrapper直接实现operator<< Could've also been implemented like this: 也可以像这样实现:

class logWrapper{
}logend;

ostream& operator<<(ostream& os, logWrapper& thislogend){
  // ...
}

If you didn't use friend , you would declare that operator<< as a member function of logWrapper . 如果你没有使用friend ,你会声明该operator<<作为logWrapper的成员函数。 It's easier to understand with a normal function: 使用普通函数更容易理解:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM