Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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 foo which 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())?

like image 809
Swapna Avatar asked Feb 22 '10 23:02

Swapna


People also ask

Why do we use friend function and static function?

In this, it can access private and public members of the class. It is denoted by placing a static keyword before the function name. It is denoted by placing a friend keyword before the function name. This function is generally used to make function members independent of any particular object of the class.

When would you use a friend function?

They are used in situations where we want a certain class to have access to another class's private and protected members. Classes declared as friends to any another class will have all the member functions become friend functions to the friend class. Friend functions are used to work as a link between the classes.

What static member functions and where it is used?

A static member function shares the single copy of the member function to any number of the class' objects. We can access the static member function using the class name or class' objects. If the static member function accesses any non-static data member or non-static member function, it throws an error.


3 Answers

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

  1. access to internals of class
  2. are in the scope of the class
  3. must be invoked on an instance

friends get only 1.

static functions get 1 and 2.

like image 123
pm100 Avatar answered Oct 18 '22 19:10

pm100


The question seems to address the situation where the programmer needs to introduce a function that does not work on any instance of a class (hence the possibility of choosing a static member 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():

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 semantics of f() and A (I'll come back to this later), this limited scenario has an easy answer: the static function is preferable. I see two reasons for this.


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 static function f() on their interface, this would allow us writing one single function that invokes f() generically on any such class.

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.

REDUNDANT DECLARATIONS:

The second reason is that if we 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():

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 A with the following declaration:

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.

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 N before the name N::f could be used legally.

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

  • The declaration inside namespace N before A's definition;
  • The friend declaration inside A's definition;
  • The definition of f() inside namespace N.

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


SEMANTIC CONSIDERATIONS:

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

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

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

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

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

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 friend and the static member 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).

The remaining differences are stylistic: whether we want to write the static keyword or the friend keyword 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.

like image 37
Andy Prowl Avatar answered Oct 18 '22 19:10

Andy Prowl


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

You use friend when you want to intentionally indicate a strong coupling and special relationship between two unrelated classes or between a class and a function.

You use static member function when the function is logically a part of the class to which it is a member.

like image 13
Alok Save Avatar answered Oct 18 '22 18:10

Alok Save