C++, static vs. namespace vs. singleton
I already read a lot of posts and articles all over the net, but I couldn't find a definite answer about this.
I have some functions with similar purposes that I want to have out of the global scope. Some of them need to be public, others should be private (because they are only helper fu开发者_如何转开发nctions for the "public" ones). Additionally, I don't have only functions, but also variables. They are only needed by the "private" helper functions and should be private, too.
Now there are the three ways:
- making a class with everything being static (contra: potential "Cannot call member function without object" - not everything needs to be static)
- making a singleton class (contra: I WILL need the object)
- making a namespace (no private keyword - why should I put it in a namespace at all, then?)
What would be the way to take for me? Possible way of combining some of these ways?
I thought of something like:
- making a singleton, the static functions use the helper function of the singleton object (is this possible? I'm still within the class, but accessing an object of it's type)
- constructor called at programm start, initializes everything (-> making sure the statics can access the functions from the singleton object)
- access the public functions only through MyClass::PublicStaticFunction()
Thanks.
As noted, using global variables is generally bad engineering practice, unless absolutely needed of course (mapping hardware for example, but that doesn't happen THAT often).
Stashing everything in a class is something you would do in a Java-like language, but in C++ you don't have to, and in fact using namespaces here is a superior alternative, if only:
- because people won't suddenly build instances of your objects: to what end ?
- because no introspection information (RTTI) is generated for namespaces
Here is a typical implementation:
// foo.h
#ifndef MYPROJECT_FOO_H_INCLUDED
#define MYPROJECT_FOO_H_INCLUDED
namespace myproject {
void foo();
void foomore();
}
#endif // MYPROJECT_FOO_H_INCLUDED
// foo.cpp
#include "myproject/foo.h"
namespace myproject {
namespace {
typedef XXXX MyHelperType;
void bar(MyHelperType& helper);
} // anonymous
void foo() {
MyHelperType helper = /**/;
bar(helper);
}
void foomore() {
MyHelperType helper = /**/;
bar(helper);
bar(helper);
}
} // myproject
The anonymous namespace neatly tucked in a source file is an enhanced private
section: not only the client cannot use what's inside, but he does not even see it at all (since it's in the source file) and thus do not depend on it (which has definite ABI and compile-time advantages!)
Don't make it a singleton
For public helper functions that don't directly depend on these variables, make them non-member functions. There's nothing gained by putting them in a class.
For the rest, put it in a class as normal non-static members. If you need a single globally accessible instance of the class, then create one (but don't make it a singleton, just a global).
Otherwise, instantiate it when needed.
The classic C way of doing this, which seems to be what you want, is to put the public function declarations in a header file, and all the implementation in source file, making the variables and non-public functions static. Otherwise just implement it as a class - I think you are making a bit of a mountain out of a molehill here.
What about using a keyword static
at global scope (making stuff local to the file) as a privacy substitute?
From your description it looks like you have methods and data that interact with each other here, in other words it sounds to me like you actually want a non-singleton class to maintain the state and offer operations upon that state. Expose your public functions as the interface and keep everything else private.
Then you can create instance(s) as needed, you don't have to worry about init order or threading issues (if you have one per thread), and only clients that need access will have an object to operate upon. If you really need just one of these for the entire program you could get away say a global pointer that's set in main
or possibly an instance
method, but those come with their own sets of problems.
Remember that the singleton instance of a singleton class is a valid instance, so it is perfectly able to be the recipient of nonstatic member functions. If you expose your singleton factory as a static function then have all of your public functionality as public nonstatic member functions and your private functionality as private nonstatic member functions, anyone that can get at the class can access the public functionality by simply invoking the singleton factory function.
You don't describe whether all of the functionality you're trying to wrap up is as related as to justify being in the same class, but if it is, this approach might work.
If you take a "C-like" approach and just use top-level functions, you can make them private by declaring them in the .cpp file rather than the publicly-included .h file. You should also make them static (or use an anonymous namespace) if you take that approach.
精彩评论