Tho*_* G. 6 c++ typedef namespaces using header
通过我的一个项目,我将进入C++领域.基本上我来自Java背景,并想知道如何在C++世界中实现Java包的概念.这使我了解了名称空间的C++概念.
到目前为止,我对命名空间绝对不错,但是当涉及到头文件时,就完全限定的类名,using-directives和using-declarations来说,事情变得有点低效.
这个问题的一个很好的说明是本文章由Herb萨特.
据我所知,这一切归结为:如果您编写头文件,请始终使用完全限定的类型名称来引用其他名称空间中的类型.
这几乎是不可接受的.由于C++标头通常提供类的声明,因此最大可读性具有最高优先级.完全有资格从不同的命名空间每种类型产生大量视觉噪声的,最终削弱了头的可读性,其程度提出了一个问题,即是否在所有使用的命名空间.
不过我想利用C++命名空间,所以想一想:如何克服C++头文件的命名空间邪恶?经过一些研究,我认为typedef可能是解决这个问题的有效方法.
下面你将找到一个C++示例程序,它演示了我如何使用公共类作用域typedef从其他名称空间导入类型.该程序在语法上是正确的,并在MinGW W64上编译良好.到目前为止一切都那么好,但我不确定这种方法是否能乐于从标题中删除using关键字,但会引入另一个我根本不知道的问题.就像Herb Sutter描述的东西一样棘手.
那就是我恳请所有对C++有深入了解的人来审查下面的代码,让我知道这是否有效.谢谢你的想法.
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_ */
Run Code Online (Sandbox Code Playgroud)
MyFirstClass.cpp
#include "MyFirstClass.hpp"
using com::company::package1::MyFirstClass;
MyFirstClass::MyFirstClass()
{
}
MyFirstClass::~MyFirstClass()
{
}
Run Code Online (Sandbox Code Playgroud)
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's 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_ */
Run Code Online (Sandbox Code Playgroud)
MySecondClass.cpp
#include "MySecondClass.hpp"
/*
* According to Herb Sutter's "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 -
* e.g. 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;
}
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
Mac*_*cke 18
通过降低复杂性来缓解疼痛.你正在将C++变成Java.(这与尝试其他方式一样糟糕.)
一些提示:
using namespace标题中的任何指令.(并且在C++文件中小心使用,如果有的话.首选内部函数.)namespace bll = boost::lambda;.这会创建非常简洁的快捷方式.PS:感谢@KillianDS评论中的一些好的提示(当我将它们编辑到问题中时被删除了.)