C++ 你会在哪里使用友元函数和静态成员函数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2315166/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 23:00:13  来源:igfitidea点击:

Where would you use a friend function vs. a static member function?

c++friend-functionstatic-functions

提问by Swapna

We make a non-member function a friend of a class when we want it to access that class's private members. This gives it the same access rights as a static member function would have. Both alternatives would give you a function that is not associated with any instance of that class.

当我们希望非成员函数访问该类的私有成员时,我们将其设为该类的友元。这赋予它与静态成员函数相同的访问权限。这两种选择都会为您提供一个与该类的任何实例都没有关联的函数。

When must we use a friend function? When must we use a static function? If both are viable options to solve a problem, how do we weigh up their suitability? Is there one that should be preferred by default?

我们什么时候必须使用友元函数?我们什么时候必须使用静态函数?如果两者都是解决问题的可行选择,我们如何权衡它们的适用性?是否有一个应该被默认首选?

For example, when implementing a factory that creates instances of class foowhich only has a private constructor, should that factory function be a static member of foo(you would call foo::create()) or should it be a friend function (you would call create_foo())?

例如,当实现一个创建类实例的工厂时,该类的实例foo只有一个私有构造函数,该工厂函数应该是foo(你会调用foo::create())的静态成员还是它应该是一个友元函数(你会调用create_foo())?

回答by pm100

Section 11.5 "The C++ Programming Language" by Bjarne Stroustrup states that ordinary member functions get 3 things:

Bjarne Stroustrup 的第 11.5 节“C++ 编程语言”指出,普通成员函数得到 3 件事:

  1. access to internals of class
  2. are in the scope of the class
  3. must be invoked on an instance
  1. 访问类的内部
  2. 在类的范围内
  3. 必须在实例上调用

friends get only 1.

friends 只得到 1。

staticfunctions get 1 and 2.

static函数得到 1 和 2。

回答by Andy Prowl

The question seems to address the situation where the programmer needs to introduce a function that does notwork on any instanceof a class (hence the possibility of choosing a staticmember function). Therefore, I will limit this answer to the following design situation, where the choice is between a static function f()and a friend free function f():

这个问题似乎解决在程序员需要引进,做一个功能的情况进行任何操作实例类(选择的,因此可能性的static成员函数)。因此,我将这个答案限制在以下设计情况下,在静态函数f()和朋友自由函数之间进行选择f()

struct A
{
    static void f();     // Better this...
private:
    friend void f();  // ...or this?
    static int x;
};

int A::x = 0;

void A::f() // Defines static function
{
    cout << x;
}

void f() // Defines friend free function
{
    cout << A::x;
}

int main()
{
    A::f(); // Invokes static function
    f();    // Invokes friend free function
}

Without knowing anything in advance about the semanticsof f()and A(I'll come back to this later), this limited scenario has an easy answer: the staticfunction is preferable. I see two reasons for this.

如果没有事先对一无所知的语义f()A(我稍后再回来这一点),这有限的情况下有一个简单的答案:static功能是优选的。我认为有两个原因。



GENERIC ALGORITHMS:

通用算法:

The main reason is that a template such as the following can be written:

主要原因是可以编写如下模板:

template<typename T> void g() { T::f(); }

If we had two or more classes that have a staticfunction f()on their interface, this would allow us writing one single function that invokes f()generically on any such class.

如果我们有两个或更多的类在它们的接口上有一个static函数f(),这将允许我们编写一个单一的函数来f()对任何这样的类进行泛型调用。

There is no way to write an equivalent generic function if we make f()a free, non-member function. Although it is true that we could put f()into a namespace, so that the N::f()syntax could be used to mimic the A::f()syntax, it would still be impossible to write a template function such as g<>()above, because namespace names are not valid template arguments.

如果我们创建f()一个免费的非成员函数,就没有办法编写等效的泛型函数。尽管我们确实可以放入f()一个命名空间,以便N::f()可以使用语法来模拟A::f()语法,但仍然无法编写像g<>()上面这样的模板函数,因为命名空间名称不是有效的模板参数。

REDUNDANT DECLARATIONS:

冗余声明:

The second reason is that ifwe were to put the free function f()in a namespace, we would not be allowed to inline its definition directly in the class definition without introducing any other declaration for f():

第二个原因是,如果我们将 free 函数f()放在命名空间中,我们将不允许直接在类定义中内联它的定义而不引入任何其他声明f()

struct A
{
    static void f() { cout << x; } // OK
private:
    friend void N::f() { cout << x; } // ERROR 
    static int x;
};

In order to fix the above, we would to preceed the definition of class Awith the following declaration:

为了解决上述问题,我们将在类的定义之前A添加以下声明:

namespace N
{
    void f(); // Declaration of f() inside namespace N
}

struct A
{
    ...
private:
    friend void N::f() { cout << x; } // OK
    ...
};

This, however, defeats our intention of having f()declared and defined in just one place.

然而,这违背了我们f()在一个地方声明和定义的意图。

Moreover, if we wanted to declare and define f()separately while keeping f()in a namespace, we would still have to introduce a declaration for f()before the class definition for A: failing to do so would cause the compiler to complain about the fact that f()had to be declared inside namespace Nbefore the name N::fcould be used legally.

此外,如果我们想f()在保留f()在命名空间中的同时分别声明和定义,我们仍然必须f()在类定义 for 之前引入一个声明A:如果不这样做会导致编译器抱怨f()必须在内部声明的事实N名称N::f可以合法使用之前的名称空间。

Thus, we would now have f()mentioned in threeseparate places rather than just two (declaration and definition):

因此,我们现在会f()三个不同的地方而不是仅仅两个(声明和定义)提到:

  • The declaration inside namespace Nbefore A's definition;
  • The frienddeclaration inside A's definition;
  • The definition of f()inside namespace N.
  • 定义N之前A的命名空间内的声明;
  • 定义friend里面的声明A
  • f()内部命名空间的定义N

The reason why the declaration and definition of f()inside Ncannot be joined (in general) is that f()is supposed to access the internals of Aand, therefore, A's definition must be seen when f()is defined. Yet, as previously said, f()'s declaration inside Nmust be seen before the corresponding frienddeclaration inside of Ais made. This effectively forces us to split the declaration and the definition of f().

f()inside的声明和定义N不能连接的原因(通常)f()是应该访问的内部结构A,因此,A在定义时必须看到f()的定义。然而,正如前文所说,f()的声明中N,必须相应见过friend的声明中A作出。这有效地迫使我们拆分声明和定义f()



SEMANTIC CONSIDERATIONS:

语义考虑:

While the above two points are universally valid, there are reasons why one might prefer declaring f()as staticover making it a friendof Aor vice versa which are driven by the universe of discourse.

虽然上述两点普遍适用,但有一些原因可能会导致人们更愿意将其声明f()statica friendofA或反之亦然,这是由话语领域驱动的。

To clarify, it is important to stress the fact that a member function of a class, whether it is staticor non-static, is logically part ofthat class. It contributes to its definition and thus provides a conceptual characterization of it.

为了澄清,重要的是要强调一个类的成员函数,无论它是static或非static,在逻辑上都是该类的一部分。它有助于它的定义,因此提供了它的概念特征。

On the other hand, a friendfunction, in spite of being granted access to the internal members of the class it is friend of, is still an algorithm which is logically externalto the definition of the class.

在另一方面,一个friend函数,尽管被授予访问类它是朋友的内部成员,仍然是一种算法,在逻辑上是外部的类的定义。

A function can be friendof more than one class, but it can be member of just one.

一个函数可以friend属于多个类,但它只能是一个 的成员

Thus, in a particular application domain, the designer may want to keep into consideration the semanticsof both the function and the class when deciding whether to make the former a friendor a member of the latter (this applies not only to staticfunctions, but to non-staticfunctions as well, where other language constraints may intervene).

因此,在特定的应用程序域中,设计者在决定是使前者成为a 成员还是后者的成员时,可能希望同时考虑函数和类的语义friend(这不仅适用于static函数,也适用于非函数)。 -static功能以及其他语言限制可能会干预的地方)。

Does the function logically contribute to characterize a class and/or its behavior, or is it rather an external algorithm? This question can't be answered without knowledge of the particular application domain.

该函数是否在逻辑上有助于表征一个类和/或其行为,或者它是一种外部算法?如果不了解特定的应用领域,就无法回答这个问题。



TASTE:

品尝:

I believe that any argument other the ones just given stems purely from a matter of taste: both the free friendand the staticmember approach, in fact, allow to clearly state what the interface of a class is into one single spot (the class's definition), so design-wise they are equivalent (modulo the above observations, of course).

我相信,除了刚才给出的那些论点之外,任何论点都纯粹出于品味:事实上,免费friendstatic成员方法都允许在一个点(类的定义)中清楚地说明类的接口是什么,所以在设计上它们是等效的(当然,以上述观察为模)。

The remaining differences are stylistic: whether we want to write the statickeyword or the friendkeyword when declaring a function, and whether we want to write the A::class scope qualifier when defining the class rather than the N::namespace scope qualifier. Thus, I will not comment further on this.

剩下的区别是风格上的:在声明函数时我们是要写static关键字还是friend关键字,以及A::在定义类时是否要写类范围限定符而不是N::命名空间范围限定符。因此,我不会对此作进一步评论。

回答by Alok Save

The difference is clearly expressing the intent of the relationship between the class and the function.

区别在于明确表达了类和函数之间关系的意图。

You use friendwhen you want to intentionally indicate a strong coupling and special relationship between two unrelatedclasses or between a class and a function.

您可以使用friend,当你想刻意表明两者之间的强耦合和特殊的关系无关类或类和功能之间。

You use staticmember function when the function is logically a part of the classto which it is a member.

static当函数在逻辑上是它所属类的一部分时,您可以使用成员函数。

回答by thebretness

Friend functions (and classes) can access the private and protected members of your class. There's rarely a good case for using a friend function or class. Avoid them in general.

友元函数(和类)可以​​访问类的私有成员和受保护成员。很少有使用友元函数或类的好例子。一般避免它们。

Static functions may only access static data (that is, class-scoped data). They may be called without creating an instance of your class. Static functions are great for circumstances you want all of the instances of your class to behave the same way. You can use them:

静态函数只能访问静态数据(即类范围的数据)。可以在不创建类的实例的情况下调用它们。静态函数非常适合您希望类的所有实例以相同方式运行的情况。您可以使用它们:

  • as callback functions
  • 作为回调函数
  • to manipulate class-scoped members
  • 操作类范围的成员
  • to retrieve constant data that you don't want to enumerate in your header file
  • 检索您不想在头文件中枚举的常量数据
  • 回答by synepis

    Static functions are used when you want a function that is the same for every instance of a class. Such functions do not have access to "this" pointer and thus cannot access any non static fields. They are used often when you want a function that can be used without instantiating the class.

    当您想要一个对类的每个实例都相同的函数时,将使用静态函数。此类函数无法访问“this”指针,因此无法访问任何非静态字段。当您想要一个无需实例化类即可使用的函数时,通常会使用它们。

    Friend functions are functions which are not in the class and you want to give them access to private members of your class.

    友元函数是不在类中的函数,您希望它们可以访问类的私有成员。

    And this(static vs. friend) is not a matter of using one vs the other since they are not opposites.

    这(静态与朋友)不是使用一个与另一个的问题,因为它们不是对立的。

    回答by Jagannath

    The standard requires that operator = () [] and -> must be members, and class-specific
    operators new, new[], delete and delete[] must be static members. If the situation
    arises where we don't need the object of the class to invoke a function, then make
    the function static. For all other functions:
    if a function requires the operators = () [] and -> for stream I/O,
    or if it needs type conversions on its leftmost argument, or if it can be implemented using the class' public interface alone, make it nonmember ( and friend if needed in the first two cases)
    if it needs to behave virtually,
    add a virtual member function to provide the virtual behaviour
    and implement in terms of that
    else
    make it a member.

    标准要求operator = ()[] 和-> 必须是成员,类特定的
    运算符new、new[]、delete 和delete[] 必须是静态成员。如果
    出现不需要类的对象来调用函数的情况,则将函数设为
    静态。对于所有其他函数:
    如果一个函数需要运算符 = () [] 和 -> 用于流 I/O,
    或者如果它需要在其最左边的参数上进行类型转换,或者如果它可以单独使用类的公共接口来实现,
    如果它需要
    虚拟行为
    ,则使其成为非成员(如果需要,在前两种情况下为友元),添加一个虚拟成员函数来提供虚拟行为并根据
    其他情况实现
    让它成为会员。

    回答by tp1

    Static function can only access members of oneclass. Friend function has access to several classes, as explained by the following code:

    静态函数只能访问一个类的成员。Friend 函数可以访问多个类,如以下代码所述:

    class B;
    class A { int a; friend void f(A &a, B &b); };
    class B { int b; friend void f(A &a, B &b); };
    void f(A &a, B &b) { std::cout << a.a << b.b; }
    

    f() can access data of both A and B class.

    f() 可以访问 A 类和 B 类的数据。

    回答by nav

    • One reason to prefer a friend over static member is when the function needs to be written in assembly (or some other language).

      For instance, we can always have an extern "C" friend function declared in our .cpp file

      class Thread;
      extern "C" int ContextSwitch(Thread & a, Thread & b);
      
      class Thread
      {
      public:
          friend int ContextSwitch(Thread & a, Thread & b);
          static int StContextSwitch(Thread & a, Thread & b);
      };
      

      And later defined in assembly:

                      .global ContextSwitch
      
      ContextSwitch:  // ...
                      retq
      

      Technically speaking, we could use a static member function to do this, but defining it in assembly won't be easy due to name mangling (http://en.wikipedia.org/wiki/Name_mangling)

    • Another situation is when you need to overload operators. Overloading operators can be done only through friends or non-static members. If the first argument of the operator is not an instance of the same class, then non-static member would also not work; friend would be the only option:

      class Matrix
      {
          friend Matrix operator * (double scaleFactor, Matrix & m);
          // We can't use static member or non-static member to do this
      };
      
    • 更喜欢朋友而不是静态成员的一个原因是当函数需要用汇编(或某种其他语言)编写时。

      例如,我们总是可以在 .cpp 文件中声明一个 extern "C" 友元函数

      class Thread;
      extern "C" int ContextSwitch(Thread & a, Thread & b);
      
      class Thread
      {
      public:
          friend int ContextSwitch(Thread & a, Thread & b);
          static int StContextSwitch(Thread & a, Thread & b);
      };
      

      后来在程序集中定义:

                      .global ContextSwitch
      
      ContextSwitch:  // ...
                      retq
      

      从技术上讲,我们可以使用静态成员函数来做到这一点,但由于名称修改(http://en.wikipedia.org/wiki/Name_mangling),在程序集中定义它并不容易

    • 另一种情况是当您需要重载运算符时。重载运算符只能通过朋友或非静态成员来完成。如果运算符的第一个参数不是同一个类的实例,那么非静态成员也不起作用;朋友将是唯一的选择:

      class Matrix
      {
          friend Matrix operator * (double scaleFactor, Matrix & m);
          // We can't use static member or non-static member to do this
      };
      

    回答by San Jacinto

    You would use a static function if the function has no need to read or modify the state of a specific instance of the class (meaning you don't need to modify the object in memory), or if you need to use a function pointer to a member function of a class. In this second instance, if you need to modify the state of the resident object, you would need to pass thisin and use the local copy. In the first instance, such a situation may happen where the logic to perform a certain task is not reliant on an object's state, yet your logical grouping and encapsulation would have it be a member of a specific class.

    如果函数不需要读取或修改类的特定实例的状态(意味着您不需要修改内存中的对象),或者如果您需要使用函数指针,您将使用静态函数一个类的成员函数。在第二个实例中,如果您需要修改常驻对象的状态,则需要传入this并使用本地副本。在第一种情况下,可能会发生这种情况,即执行特定任务的逻辑不依赖于对象的状态,但您的逻辑分组和封装将使其成为特定类的成员。

    You use a friend function or class when you have created code that is not a member of your class and should not be a member of your class, yet has a legitimate purpose for circumventing the private/protected encapsulation mechanisms. One purpose of this may be that you have two classes that have need of some common data yet to code the logic twice would be bad. Really, I have only used this functionality in maybe 1% of the classes I've ever coded. It is rarely needed.

    当您创建的代码不是您的类的成员并且不应该是您的类的成员,但具有规避私有/受保护封装机制的合法目的时,您可以使用友元函数或类。这样做的一个目的可能是您有两个类需要一些公共数据,但对逻辑进行两次编码会很糟糕。真的,我只在 1% 的我曾经编写过的类中使用了这个功能。很少需要它。

    回答by UserXYZ

    A friend function can not be inherited while a static function can be. So when an aim can be achieved with both static function and friend function, think that whether you want to inherit it or not.

    友元函数不能被继承,而静态函数可以。所以当一个目的既可以用静态函数又可以用友元函数实现的时候,考虑要不要继承。