Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any advantage to implementing functions as free functions rather than members in C++?

I'm interested in the technical logistics. Is there any advantage, such as memory saved, etc., to implementing certain functions dealing with a class?

In particular, implementing operator overloads as free functions (providing you don't need access to any private members, and even then you can make them use a friend non-member)?

Is a distinct memory address provided for each function of the class each time an object is created?

like image 308
DeiDei Avatar asked Apr 23 '16 10:04

DeiDei


People also ask

When would you use a non-member function?

Non-member functions are commonly used when the developer of a library wants to write binary operators that can be overloaded on either argument with a class type, since if you make them a member of the class you can only overload on the second argument (the first is implicitly an object of that class).

What is the advantage of static member function?

Static function: Advantage: it could be called without existing real object. Static member functions become useful when you want the class as a whole to have a function, instead of each individual object. With a static member function, you can then change static variable data.

Why do we use member functions?

The main aim of using the member function is to provide modularity to a program, which is generally used to improve code reusability and to make code maintainable.

What is the difference between a member function of a class and a non-member function?

A member function is declared in the class but defined outside the class and is called using the object of the class. A non-member function that is declared outside the class but called a normal function inside the main function.


2 Answers

The most important thing to consider when designing classes is, "what is the invariant?" Classes are design to protect invariants. So, classes must be the tiniest as possible to ensure that invariant is properly protected. If you have so many member/friend functions, there is more code to review.

From this point of view, if a class has members which don't need to be protected (for example, a boolean which its corresponding get/set functions can be freely changed by the user), is better to put that attributes as public and remove the get/set functions (more or less, these are the Bjarne Stroustrup words).

So, which functions must be declared inside the class and which ones out? Inside functions must be these minimum required set of function to protect the invariant, and outside functions must be any function that can be implemented using the other ones.

The thing with operator overloading is another history, because the criteria to put some operators inside, and some other outside, is because of syntactical issues related to implicit conversions and so on:

class A
{
private:
   int i_i;

public:
   A(int i) noexcept : i_i(i) {}
   int val() const noexcept { return i_i; }

   A operator+(A const& other) const noexcept
   { return A(i_i + other.i_i); }
};

A a(5);
cout << (4 + a).val() << endl;

In this case, since the operator is defined inside the class, the compiler doesn't find the operator, because the first argument is an integer (when an operator is called, the compiler search for free functions and functions declared inside the class of the first argument).

When declared outside:

class A
{
private:
   int i_i;

public:
   A(int i) noexcept : i_i(i) {}
   int val() const noexcept { return i_i; }
};

inline A operator+(A const& first, A const& other) const noexcept;
{ return A(first.val() + other.val()); }

A a(5);
cout << (4 + a).i_i << endl;

In these case, the compiler find the operator, and try to perform an implicit conversion of the first parameter from int to A, using the proper A's constructor.

In these case, the operator can also be implemented using other functions, so, it doesn't need to be friend and you can be sure the invariant is not compromised with that additional function. So, in these concrete example, moving the operator outside is good for two reasons.

like image 124
Peregring-lk Avatar answered Oct 02 '22 15:10

Peregring-lk


There are various articles about circumstances when implementing functionality using non-member functions is preferred over function members.

Examples include

Scott Meyers (author of books like "Effective C++", "Effective STL", and others) on how non-members improve encapsulation: http://www.drdobbs.com/cpp/how-non-member-functions-improve-encapsu/184401197

Herb Sutter in his Guru of the Week series #84 "Monoliths Unstrung". Essentially he advocates, when it is possible to implement functionality as a member or as a non-member non-friend, prefer the non-member option. http://www.gotw.ca/gotw/084.htm

like image 32
Peter Avatar answered Oct 02 '22 15:10

Peter