0

can i declare functions private in header files?
imagine that you use a function declared outside the class and you only want be used only by that class... how can i private that function?

2
Contributors
1
Reply
14
Views
2 Years
Discussion Span
Last Post by mike_2000_17
0

Why do you need to put it in the header?

Ok, let's just assume this example:

// my_foo.hpp:

#ifndef MY_FOO_HEADER
#define MY_FOO_HEADER

void foo_impl();  // <-- this is the function you want to "hide"

class bar {
  public:
    void foo();  // <-- this is the function that uses the foo_impl function.
};

#endif

// my_foo.cpp:

#include "my_foo.hpp"

void foo_impl() {
  /* some code */
};

void bar::foo() {
  foo_impl();
};

So, if we assume that foo_impl is not going to be useful anywhere else, then the main thing to do is remove the declaration from the header and remove the external linkage on the definition ("external linkage" means that it's visible by the compiler / linker as a function that can be called from other source files). There are two ways to remove external linkage: give it a static specifier, or put it in an unnamed namespace. In the first case:

// my_foo.hpp:

#ifndef MY_FOO_HEADER
#define MY_FOO_HEADER

class bar {
  public:
    void foo();
};

#endif

// my_foo.cpp:

#include "my_foo.hpp"

// NOTE the 'static' here:
static void foo_impl() {
  /* some code */
};

void bar::foo() {
  foo_impl();
};

The word "static" applied to a function just tells the compiler not to make this function visible outside of this translation unit (we call that "internal linkage"). You can also achieve the same effect for a whole collection of things by putting them in an unnamed namespace, as so:

// my_foo.hpp:

#ifndef MY_FOO_HEADER
#define MY_FOO_HEADER

class bar {
  public:
    void foo();
};

#endif

// my_foo.cpp:

#include "my_foo.hpp"

namespace {  // <-- open a namespace, with no name

void foo_impl() {
  /* some code */
};

};

void bar::foo() {
  foo_impl();
};

Everything inside an unnamed namespace is only visible to the current translation unit (cpp file), i.e., it will not have linkage. It's essentially the same as with static, except that it can be nicer for hiding a lot of stuff, instead of marking everything with static.

If you absolutely have to put the function inside the header, e.g., because you use it in a template, then you can't really hide it completely. You can still use static, inline or an unnamed namespace if you define the function in the header and don't want it to have external linkage. But you cannot do that if you want to put its definition in a cpp file, because that requires external linkage to link the declaration (in the header) with the definition (in the cpp file).

One thing you can do to make it "private" is to actually make a private static member function of the class that uses it. Another option is to make a private static member function of another class, and make the main class a friend of it, such that it can call that static member function.

But typically, the convention is simply to put the function in a "detail" namespace. It is a convention in C++ that whatever is in a "detail" namespace are things that people should not use or call directly, i.e., it is only an implementation detail used by the library code. In this case, you just do:

// my_foo.hpp:

#ifndef MY_FOO_HEADER
#define MY_FOO_HEADER

/* this tells other people "nothing to see here, move along" */
namespace detail {

void foo_impl();

};

class bar {
  public:
    void foo();  // <-- this is the function that uses the foo_impl function.
};

#endif

// my_foo.cpp:

#include "my_foo.hpp"

namespace detail {

void foo_impl() {
  /* some code */
};

};

void bar::foo() {
  detail::foo_impl();
};

This is the most widely used technique for where you have to declare / define helper functions or classes in header files, while giving a clear message that they are only implementation details and should not be used by others. But, of course, that cannot actually stop someone from using them (unlike "private" which will not compile if people try to call it). But the reality is, even things that are "private" can be called if you know the right tricks.

There is no solution that is completely water-proof, but if you can avoid having to declare the function in the header (as with the solutions above), then you can remove the external linkage, and at that point, the function is essentially impossible to access from anywhere else, and will be completely invisible to outside code.

This topic has been dead for over six months. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.