Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

static member utility-function vs Non-member utility-function

Tags:

c++

I've read some other questions here and did not find any definitive answer.

background

for analogy, assume there is a node class and that I'd want to get a graph of the connected nodes from this one. For this I'd need a function get_graph().

first try:

the function is a regular member function of the Node class:

class Node
{
    //impl...
    GraphObj get_graph();
}

I don't like this one since a graph is not a functionality of the node class. It's rather a query upon some instances of Node.

second try:

the function is a static member function of the Node class:

class Node
{
    //impl...
    static GraphObj get_graph();
}

this is better because now I've decoupled the function from an instance. But still, I don't feel comfortable that this function is part of the class.

third try:

the function is a free function in the same namespace/TU:

class Node
{
    //impl...
}
GraphObj get_graph(Node* graph_source);

Now it's really decoupled! I don't want the user of this class to miss this functionality. Also, this function can only act on this class, so can it be too much decoupled?

tl;dr

how should you decide how to expose a function related to a class? particularly exposing the function as:

  1. regular member function.
  2. static member function.
  3. free function taking an instance of the class.
  4. something else?
like image 856
Eyal Kamitchi Avatar asked Sep 15 '25 06:09

Eyal Kamitchi


1 Answers

Scott Meyer's article on member- vs. free functions is highly relevant here;

If you're writing a function that can be implemented as either a member or as a non-friend non-member, you should prefer to implement it as a non-member function. That decision increases class encapsulation.

Checkout the article for the explanation.

The question whether member functions should be static or not is another issue. Generally, make them static if they aren't coupled to a particular instance. Examples are utility functions for setting up the state of the object depending on constructor arguments, e.g.

A::A(int someArg) :
  dataMember{computeInitialState(someArg)}

Here, computeInitialState should be static. Another example are named constructors, e.g. Point::cartesian(double x, double y) - this should be static, too.

like image 177
lubgr Avatar answered Sep 17 '25 18:09

lubgr