Home > Blockchain >  How to "hide" utility functions in cpp -- code design question?
How to "hide" utility functions in cpp -- code design question?

Time:07-15

I have a utility package of functions that really don't fit into a class, as they effectively are a set of functionality across two classes (and due to MISRA, can't put them in a class that inherits both).

The code structure is as follows, in the body (cpp) file:

namespace myName {
   void a(args)
   {
   // some stuff here
   }

   void b(args)
   {
   // some stuff here 
   }

   void c(args)
   {
      a(args);
      b(args);
   }
}

Now, I want to call c elsewhere in other classes. However, a and b should not be called anywhere else, yet the compile says I need to put all three in the header file. If I were using classes, a and b would therefore go into the private area, or be declared static. If I were using Ada, they'd be local functions within c.

This is not an opinion question, the answer just needs to fulfil the following (to iterate):
How can I not expose a and b in this utility package without the use of a class?

(The answer might actually be "use a class and restructure your code properly.)

CodePudding user response:

You can have the header expose the interface which you want exposed to the user, and have the helpers encapsulated within another cpp file.

It would look something like this:

/**
 * @file my_name.hpp
 */
#pragma once

namespace my_name {
   extern void c(void *args);
}
/**
 * @file my_name.cpp
 */

namespace my_name 
{
    static inline void a(void *args)
    {
        // some stuff here
    }

    static inline void b(void *args)
    {
        // some stuff here 
    }

    void c(void *args)
    {
        a(args);
        b(args);
    }
}
/**
 * @file main.cpp
 */

#include "my_name.hpp"

int main(int argc, char **argv)
{
    // | main.cpp:10:14: error: 'a' is not a member of 'my_name'
    // my_name::a(nullptr);
    // | main.cpp:12:14: error: 'b' is not a member of 'my_name'
    // my_name::b(nullptr);    
    my_name::c(nullptr);

    return 0;
}

If the user tries to be clever and put this code into main.cpp:

namespace my_name {
   extern void a(void *args);
   extern void b(void *args);
}

There would be a compile-time linking error when trying to call them, as they are defined static(file local).

sidenotes:

  1. You can omit the inline if you have reasons you don't want to hint inlining, I put it there as an annotation to be clear to the readers that I expect the function to be inlined, it will almost certaintly be inlined in this case by any compiler capable of doing so(as it is file-local and has no pointers to them, etc) even without the keyword. The inline keyword does not guarantee it will be inlined, and will be ignored if the compiler finds reasons not to inline it.
  2. extern on functions does nothing(as far as I am aware), I just wanted to make an explicit contrast to the static in the definition of a and b.

CodePudding user response:

Header files are "interfaces" (not in an OOP sense) of translation units. What the consumer of an API needs to see/know goes into a header. What the consumer does not need to see/know goes into a cpp.

File A.h

namespace foo {

    void a();
}

File A.cpp

namespace foo {
    void a() {
    // implementation
    }
}

File B.cpp

#include "A.h" // Make "foo::a()" visible to B

namespace bar {

    void b() {
        foo::a();
    }
}

It's perfectly valid (and also encouraged) to hide implementation details into cpp files without a header counter part.

  •  Tags:  
  • c
  • Related