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

C++ 当您声明一个朋友,然后在类中定义它时,这意味着什么?,c++,C++,我试图理解一段代码片段,我通过反复试验成功地使其工作。我理解这个代码段的所有内容,除了当我从类声明中去掉“friend”时为什么它不起作用。我不明白朋友在这种情况下在做什么 细流测井 类日志包装器{ friend ostream&operator这意味着该朋友不是该类的成员,但您可以访问静态类成员和成员类型(包括私有成员) 这使得函数“外观和感觉”像一个成员。因为操作符通常友元只是告诉编译器,操作符您同时声明和定义友元函数,这会重载操作符 声明为friend的函数可以访问与它们成为好友的类的任

我试图理解一段代码片段,我通过反复试验成功地使其工作。我理解这个代码段的所有内容,除了当我从类声明中去掉“friend”时为什么它不起作用。我不明白朋友在这种情况下在做什么


细流测井

类日志包装器{
friend ostream&operator这意味着该朋友不是该类的成员,但您可以访问
静态
类成员和成员类型(包括
私有
成员)


这使得函数“外观和感觉”像一个成员。因为
操作符通常
友元
只是告诉编译器,
操作符您同时声明和定义友元函数,这会重载操作符

声明为
friend
的函数可以访问与它们成为好友的类的任何实例的所有私有成员

这与常规成员函数(显然也可以访问私有成员)不同,因为友元函数不是类的成员——它们是独立函数


因此,由于您已经在类中定义了独立函数,乍一看似乎很混乱——请记住,它根本不是一个真正的成员函数。

除了之前编写的之外,查找规则略有不同。如果在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
的大括号内定义的,因此除非参数(至少一个参数)的类型为
B
,否则查找将不会找到
foo
,这将禁止从
A
B
的隐式转换,因为找不到潜在的重载,因此不会执行转换


这就是为什么在定义模板时,最好提供
friend
函数(特别是运算符)的实现的原因之一内联,因为这减少了函数的范围并减少了命名空间污染。

这意味着你的懒惰。但是懒惰在编程方面很好。@Martin:不仅仅是懒惰……它还有它的优点too@David罗德里格斯:是的,这就是为什么我说懒惰是好的。它隐式地记录了接口的紧密耦合和扩展。@Martin,它不仅隐式文档,但更改查找规则。如果在类括号内定义了
友元
,则除非其中一个参数为封闭类类型,否则它在封闭命名空间中将不可用。@David:这一点很好。但请注意,99.9%的时间是正确的,因为友元的目的是为它提供访问成员。因此,除非您仅访问静态成员,否则其中一个参数将是封闭的对象。因此Koenig(或AD)lookup将用于查找函数。因此,您的语句在技术上是正确的,很少是factor。很抱歉,这基本上是错误的。Friend与Static无关,您可以通过对象访问普通成员(在本例中,第二个参数是thislogend
)@Cameron:
friend
static
无关,但在
类{}
范围内定义意味着在
类{}内定义的其他名称
scope不需要限定。这包括
static
成员和成员类型。@马丁:我从来没说过你不能访问普通成员。哈?@David:这不是“类的一部分”;这就是重点。它不是一个成员函数,但为了方便/懒惰,它在类定义中被定义为友元函数定义的一部分。是的,除了:(a)它与函数定义中的w.r.t.限定规则略有不同;和(b)您忘记了类定义示例中的
friend
语句。因此,如果我将一个函数声明为类内的friend,然后定义它,它将被定义为一个全局函数?那么,结果就是更漂亮的代码了?@Tomalak:我没有,OP甚至没有使用任何变量(如果它有变量的话)对于
logWrapper
。这对于问题中提出的OP用例是特别的。@David Hinkle:您混淆了“自由函数”和“全局函数”这两个术语,但是你头脑中的想法基本上是正确的,是的。@Xeo:
friend
是这个问题的关键。如果你要展示一个例子,说明friended函数的定义是不恰当的,我认为一个好的例子应该展示类定义中留下的friend函数声明。否则,它们就是甚至不接近于同等水平。
class logWrapper{
}logend;

ostream& operator<<(ostream& os, logWrapper& thislogend){
  // ...
}
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);
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
}