为接口和实现提供单独的名称空间值得吗
Is it worth it to have separate namespaces for interfaces and implementations?
为接口和实现提供单独的名称空间值得吗?
Stroustrup在他的C++书(第四版)中的建议是,我们应该使用单独的名称空间用于接口和实现。更有经验的人能说点什么吗在这个问题上?我的意思是,这听起来不错,但它真的实用吗现实世界的项目?
名称空间告诉定义属于谁。当然,接口属于与实现不同的组是有意义的;这就是接口的全部意义,关注点的分离。
在那些需要大量实现的代码中(比如Boost中的一些元编程怪物),一眼就能发现哪些代码可以直接使用,哪些代码可以安全地忽略,这可能很有用。库的detail
命名空间中的代码被视为"内部"代码,因此当您在堆栈跟踪中看到detail
符号时,不需要花费时间搜索文档。
我不会说它有巨大的好处,当然在一般情况下也不是这样,但既然它不会造成任何伤害,你还不如保持整洁和隔离。
在现实世界的项目中有意义吗?
是的,例如在boost中,它被广泛使用。以boost::shared_ptr
为例。当我看到namespace detail
时,我立刻知道我不必太仔细地研究那个代码段,除非有错误消息告诉我要这样做(即使这样,也很可能是我的错)。
强制性设计的现实世界启发的例子
我想你知道如何驾驶汽车。有很多接口:方向盘、油门/刹车/离合器踏板、显示器等等。你有兴趣使用这些接口,毕竟,这就是你使用汽车的方式:
namespace the_company{
struct wheel{
void turnLeft(deg);
void turnRight(deg) { turnLeft(-deg); }
};
struct pedal{
void tap();
void press_completely_till_something_happens();
//!< might deadlock if using break and car isn't moving
};
struct display{
so_many_colors lookat();
};
}
为了这个例子,我们将把它们组合在一起作为一辆车,但将它们拆分成不同的名称空间不仅对OOP实用。
namespace the_company{
struct car{
public:
wheel & getWheel();
pedal & getBreakPedal();
...
};
}
我们对car
有什么期望?我们可以期待我们可以使用汽车的车轮或踏板,它会起作用:
car myCar;
myCar.getGasPedal().press_completely_till_something_happens();
// OH GOD; WHAT HAVE I DONE!?
myCar.getWheel().turnLeft(360);
myCar.getBreakPedal().press_completely_till_something_happens();
// Shew. That was close.
我们完全可以使用car
。顺便说一句,我们没有把wheel
放在car
中,因为我们公司可能会生产其他使用轮子的东西,比如船、卡车、人造飞机、阀门和其他非车辆的东西,而display
可能会被更多不同的东西使用(手机、显示器、电视,你能想到的)。
然而,为了让汽车真正运转起来,它必须有一个发动机。由于发动机是一些相当复杂的机器,我们将它们隐藏在hood
:之下
namespace the_company{
namespace hood{
struct engine{
// heavily optimized code
// not so nice interface anymore
// maybe not even documentated
...
};
}
}
engine
是一个野兽,它是可扩展的,可以适用于任何车辆或重型机械,您的公司在优化方面投入了大量精力。现在,每当车主的发动机出现问题时,他可以简单地查看hood
并检查出了什么问题。
但事实上,它隐藏在某个东西后面,从一开始就告诉用户,他应该知道自己要做什么。如果他不理解金属/代码,他应该向他的服务维护/支持部门寻求帮助。
此外,engine
可能会发生变化,甚至被完全删除,因为我们公司发明了fusion_engine
,这会带来更好的利润。
这就是namespace detail
对我的意义:复杂的细节,可能会改变,甚至可能只对最初的维护人员有意义。但没关系。它不是接口的一部分。
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 命名空间中具有.h和.cpp文件的类
- 从父命名空间重载类型
- 当在同一名称空间中有两个具有相同签名的函数时,会发生什么
- 在命名空间中定义函数还是限定函数
- C++:对不存在的命名空间使用命名空间指令
- 通过继承类使用来自不同命名空间的运算符
- 使用命名空间时出现多个定义错误
- OpenGL相机和相机空间转型的困惑
- CUDA内核和数学函数的显式命名空间
- 打印第二列时的2d字符矢量打印空间
- 嵌套的匿名命名空间
- CMakeLists.txt中的命名空间表示法
- 类是C++中的命名空间吗
- 在命名空间中使用全局命名空间中的函数
- 如何使 std::sort 在 std::swap 和我的命名空间的模板化交换之间没有名称冲突?
- '使用命名空间{嵌套在另一个命名空间中的某个命名空间}"
- 是否值得降低我的代码的可读性,以便在出现内存不足错误时提供异常安全性?
- 将几行代码写成一行是有益的(就内存和空间复杂性而言)。值得吗?
- 为接口和实现提供单独的名称空间值得吗