How to overcome the slander of C ++ header file namespace

In one of my projects I will enter the C ++ field. I mostly go from the Java background and wondered how the concept of Java packages is implemented in the C ++ world. This led me to the concept of C ++ namespaces.

I still have a good understanding of namespaces, but when it comes to header files everything becomes ineffective with regard to a fully qualified class of names, directives, and declarations.

A very good description of the problem is this article by Herb Sutter.

As I understand it, it all boils down to: if you are writing a header file always use full type names to refer to types from other namespaces.

This is almost unacceptable. Since the C ++ header usually provides a class declaration, maximum readability is of utmost importance. Fully qualifying each type from a different namespace creates a lot of visual noise, finally reducing the readability of the header to such an extent that it raises the question of whether to use namespaces at all.

However, I want to use C ++ namespaces and so the question is: How to overcome the slander of the C ++ header file namespace? After some research, I think that typedefs can be an effective way to solve this problem.

After that, you will find an example C ++ program that demonstrates how I will, for example, use types of typed types with an open class to import types from other namespaces. The program is syntactically correct and compiles on MinGW W64. So far so good, but I'm not sure if this approach happily removes the using keyword from the header, but brings another problem that I just don't know about. Just something complicated, like the things described by Herb Sutter.

I ask everyone who has a complete understanding of C ++, check out the code below and let me know if this should work or not. thanks for your thoughts.

MyFirstClass.hpp

#ifndef MYFIRSTCLASS_HPP_ #define MYFIRSTCLASS_HPP_ namespace com { namespace company { namespace package1 { class MyFirstClass { public: MyFirstClass(); ~MyFirstClass(); private: }; } // namespace package1 } // namespace company } // namespace com #endif /* MYFIRSTCLASS_HPP_ */ 

MyFirstClass.cpp

 #include "MyFirstClass.hpp" using com::company::package1::MyFirstClass; MyFirstClass::MyFirstClass() { } MyFirstClass::~MyFirstClass() { } 

MySecondClass.hpp

 #ifndef MYSECONDCLASS_HPP_ #define MYSECONDCLASS_HPP_ #include <string> #include "MyFirstClass.hpp" namespace com { namespace company { namespace package2 { /* * Do not write using-declarations in header files according to * Herb Sutter Namespace Rule #2. * * using std::string; // bad * using com::company::package1::MyFirstClass; // bad */ class MySecondClass{ public: /* * Public class-scoped typedefs instead of using-declarations in * namespace package2. Consequently we can avoid fully qualified * type names in the remainder of the class declaration. This * yields maximum readability and shows cleanly the types imported * from other namespaces. */ typedef std::string String; typedef com::company::package1::MyFirstClass MyFirstClass; MySecondClass(); ~MySecondClass(); String getText() const; // no std::string required void setText(String as_text); // no std::string required void setMyFirstInstance(MyFirstClass anv_instance); // no com::company:: ... MyFirstClass getMyFirstInstance() const; // no com::company:: ... private: String is_text; // no std::string required MyFirstClass inv_myFirstInstance; // no com::company:: ... }; } // namespace package2 } // namespace company } // namespace com #endif /* MYSECONDCLASS_HPP_ */ 

MySecondClass.cpp

 #include "MySecondClass.hpp" /* * According to Herb Sutter "A Good Long-Term Solution" it is fine * to write using declarations in a translation unit, as long as they * appear after all #includes. */ using com::company::package2::MySecondClass; // OK because in cpp file and // no more #includes following MySecondClass::MySecondClass() { } MySecondClass::~MySecondClass() { } /* * As we have already imported all types through the class scoped typedefs * in our header file, we are now able to simply reuse the typedef types * in the translation unit as well. This pattern shortens all type names * down to a maximum of "ClassName::TypedefTypeName" in the translation unit - * eg below we can simply write "MySecondClass::String". At the same time the * class declaration in the header file now governs all type imports from other * namespaces which again enforces the DRY - Don't Repeat Yourself - principle. */ // Simply reuse typedefs from MySecondClass MySecondClass::String MySecondClass::getText() const { return this->is_text; } // Simply reuse typedefs from MySecondClass void MySecondClass::setText(String as_text) { this->is_text = as_text; } // Simply reuse typedefs from MySecondClass void MySecondClass::setMyFirstInstance(MyFirstClass anv_instance) { this->inv_myFirstInstance = anv_instance; } // Simply reuse typedefs from MySecondClass MySecondClass::MyFirstClass MySecondClass::getMyFirstInstance() const { return this->inv_myFirstInstance; } 

main.cpp

 #include <cstdio> #include "MySecondClass.hpp" using com::company::package2::MySecondClass; // OK because in cpp file and // no more #includes following int main() { // Again MySecondClass provides all types which are imported from // other namespaces and are part of its interface through public // class scoped typedefs MySecondClass *lpnv_mySecCls = new MySecondClass(); // Again simply reuse typedefs from MySecondClass MySecondClass::String ls_text = "Hello World!"; MySecondClass::MyFirstClass *lpnv_myFirClsf = new MySecondClass::MyFirstClass(); lpnv_mySecCls->setMyFirstInstance(*lpnv_myFirClsf); lpnv_mySecCls->setText(ls_text); printf("Greetings: %s\n", lpnv_mySecCls->getText().c_str()); lpnv_mySecCls->setText("Goodbye World!"); printf("Greetings: %s\n", lpnv_mySecCls->getText().c_str()); getchar(); delete lpnv_myFirClsf; delete lpnv_mySecCls; return 0; } 
+6
source share
1 answer

The pain is alleviated by reducing complexity. You bend C ++ in Java. (This works as bad as trying differently.)

Some tips:

  • Remove the space level "com". (This is just hawaism that you don't need)
  • Drop the company namespace, perhaps replace the product or library namespace (i.e. boost, Qt, OSG, etc.). Just select something unique wrt other libraries that you use.
  • You do not need to fully declare names that are in the same namespace you are in (caveat emptor: template classe, see comment). Just avoid any using namespace directives in the headers. (And use with caution in C ++ files, if at all possible. Internal functions are preferred.)
  • Consider namespace aliases (in / cpp function files), i.e. namespace bll = boost::lambda; . This creates shortcuts that are pretty neat.
  • Also, by hiding private members / types with the pimpl template, your header has fewer types to expand .

PS: Thanks @KillianDS for some good advice in the comments (which were removed when I edited them into the question.)

+18
source

All Articles