Skip to content

C++ Member Functions vs. Free Functions

As a C++ programmer, you are probably familiar with the following design question: Should you implement a function as a class member or as a free function?

Not so sure about the answer? Well, let’s examine.

An Example

Here’s an example from the mesh processing library I’m working on. Let’s say you have a class SurfaceMesh for representing polygon meshes and you want to add a function that reads a mesh from different file formats.

You basically have two obvious options.

Either you add a class member:

class SurfaceMesh {
    ...
    void read(const std::filesystem::path& file);
}

Or you use a free function:

void read(SurfaceMesh& mesh, const std::filesystem::path& file);

Which option would you choose?

In the past, we used to have a member function, mostly for sake of convenience. It’s easy to discover, type, and remember. Problem solved?

SurfaceMesh mesh;
mesh.read("file.obj");

Well, not so fast. This might be the obvious solution, but it’s not necessarily the best way from a software design perspective.

In fact, there are very solid arguments for preferring free functions. Here are just a few:

And the list goes on. In fact, there is an excellent talk by Klaus Iglberger going through this question in detail. He basically argues that free functions are the preferable choice in most cases. Notably, free functions help to follow SOLID principles.

Along similar lines, Herb Sutter also recommends free functions in his C++ Coding Standards. Scott Meyers also favors free functions in Effective C++ item 23. He even came up with an algorithm to decide when to use a free function or a member function: Given a class C and a function f related to C, use the following algorithm:

if (f needs to be virtual)
{
    make f a member function of C;
}
else if (f is operator>> or operator<<)
{
    make f a non-member function;
    if (f needs access to non-public members of C)
    {
        make f a friend of C;
    }
}
else if (f needs type conversions on its left-most argument)
{
    make f a non-member function;
    if (f needs access to non-public members of C)
    {
        make f a friend of C;
    }
}
else
{
    make f a member function of C;
}

Admittedly, there are some advantages of member functions as well. For some folks they just might be easier to use. In particular, you get better IDE support for auto-completion when typing something like mesh. in the example above. There’s also a little less ambiguity since there’s at least one function argument less to worry about.

Conclusions

In general, preferring free functions seems like a very reasonable choice. I think the main counter-argument is usability and discovery. However, there also is a proposal by Bjarne Stroustrup and Herb Sutter for a unified function call syntax that would allow to simply write

mesh.read("file.stl");

if there is a function with the signature

read(Mesh mesh, const std::string& filename)

While this certainly would add some convenience, I’m not entirely sure it’s worth the added complexity. It’s not that C++ doesn’t already have enough of that!

Let me close by saying that in practice the choice is not always that obvious. There might be cases when you design an API around free functions only to later realize that some function does indeed needs access to the internals of the class. This has been exactly the case in the motivating example above, and so I resorted to a friend function. 😕

References and Further Reading