File scope data with C++ namespaces

2019-07-20 02:37发布

问题:

I've got some embedded C++ code that's currently written in a very C-like way, and I'd like to convert it to use namespaces for better code organization. Currently I hide my private file scope functions and variables in anonymous namespaces, but I'm not sure where to hide it using this new pattern. Should I still use an anonymous namespace, or is adding it to the namespace in the .cpp file, but not the header file sufficient enough to prevent external access?

More specifically, I've got code that looks like this:

UI.h

#ifndef UI_H
#define UI_H

//Public data declarations
extern int g_UiPublicVar;

//Public function declarations
void UI_PublicFunc();

#endif

UI.cpp

#include "UI.h"

//Private data and functions
namespace
{
int m_PrivateVar = 10;

void privateFunc()
{
   //Do stuff!
}
}

//Public data definitions
int g_UiPublicVar = 10;

//Public function definitions
void UI_PublicFunc()
{
   m_PrivateVar++;
   privateFunc();
}

...and I'd like to restructure it to look like this:

New UI.h

#ifndef UI_H
#define UI_H

namespace UI
{

//Public data declarations
extern int publicVar;

//Public function declarations
void publicFunc();

}

#endif

New UI.cpp

#include "UI.h"

namespace UI
{

//Public data definitions
int publicVar = 10;

//Public function definitions
void publicFunc()
{
   m_PrivateVar++;
   privateFunc();
}

}

...where should I put m_PrivateVar and privateFunc()?

回答1:

The solution is to put it in an anonymous nested namespace for the private elements:

File UI.cpp:

namespace UI
{
    namespace  // nested private namespace
    {
        int m_PrivateVar = 10;
        void privateFunc()
        {
            //Do stuff!
        }
    }
    //Public definitions
    ...
}

The other compilation units then can't see it, as the anonymous namespace is unique for each compilation unit.

You can test this setting using a third compilation unit, including UI.h and trying to create access to the private function:

File main.cpp:

#include "UI.h"
namespace UI {
    extern void privateFunc();   // Hijack temptative
}
int main(int ac, char**av) 
{
    UI::publicFunc();   // yes !! 
    UI::privateFunc();  // compiles, but generates a linking error
                        // private remains private :-)  !!!
}

Even if the hijack temptative would also use an anonymous namespace, it wouldn't work and still result in linking errors, because, as already said, the anonymous namespace is unique for each compilation unit.