15

是否存在这样一种依赖模式,以至于不可能将所有内容都保存在头文件中?如果我们只强制每个标题一个类的规则怎么办?

出于这个问题的目的,让我们忽略静态的东西:)

4

4 回答 4

7

我知道标准 C++ 中没有任何特性,除了你已经提到的静态特性,它需要一个库来定义一个完整的翻译单元(而不仅仅是标题)。但是,不建议这样做,因为这样做会强制所有客户端在库更改时重新编译他们的整个代码库。如果您使用源文件或静态库或动态库形式的分发,则可以更改/更新/修改您的库,而无需强制所有人重新编译。

于 2010-09-20T17:28:49.593 回答
5

我想说,在不使用许多语言功能的明确条件下,这是可能的:正如您所注意到的,static关键字的一些用途。

这可能需要一些技巧,但可以对其进行审查。

  1. 每当您需要打破依赖循环时,您都需要保持头文件/源代码的区别,即使这两个文件实际上是头文件。
  2. 自由函数(非模板)必须内联声明,编译器可能不会内联它们,但如果它们被声明,它不会抱怨在客户端构建其库/可执行文件时它们已被重新定义。
  3. 全局共享数据(全局变量和类静态属性)应在函数/类方法中使用本地静态属性进行模拟。实际上,就调用者而言,它无关紧要(只需添加())。请注意,在 C++0x 中,这成为首选方式,因为它保证是线程安全的,同时仍能防止初始化顺序失败,直到那时……它不是线程安全的;)

尊重这 3 点,我相信您将能够编写一个成熟的仅包含标头的库(有人看到我错过的其他内容吗?)

许多 Boost 库使用了类似的技巧来仅作为标头,即使它们的代码不是完全模板。例如Asio,非常有意识地提出了使用标志的替代方案(请参阅Asio 1.4.6 的发行说明):

  • 只需要几个功能的客户不必担心构建/链接,他们只需抓住他们需要的东西
  • 更依赖它或想要减少编译时间的客户可以构建自己的 Asio 库(使用自己的标志集),然后包含“轻量级”头文件

这样(以图书馆开发人员付出更多努力为代价)客户得到他们的蛋糕并吃掉它。我认为这是一个非常好的解决方案。

注意:我想知道static函数是否可以内联,我更喜欢自己使用匿名命名空间,所以从来没有真正研究过它......

于 2010-09-20T19:24:54.067 回答
2

The one class per header rule is meaningless. If this doesn't work:

#include <header1>
#include <header2>

then some variation of this will:

#include <header1a>
#include <header2>
#include <header1b>

This might result in less than one class per header, but you can always use (void*) and casts and inline functions (in which case the 'inline' will likely be duly ignored by the compiler). So the question, seems to me, can be reduced to:

class A
{
// ...
void *pimpl;
}

Is it possible that the private implementation, pimpl, depends on the declaration of A? If so then pimpl.cpp (as a header) must both precede and follow A.h. But Since you can always, once again, use (void*) and casts and inline functions in preceding headers, it can be done.

Of course, I could be wrong. In either case: Ick.

于 2010-09-20T17:59:41.507 回答
1

在我漫长的职业生涯中,我还没有遇到过不允许仅使用标头实现的依赖模式。

请注意,如果类之间存在循环依赖关系,您可能需要求助于抽象接口 - 具体实现范例,或使用模板(使用模板允许您前向引用模板参数的属性/方法,这些属性/方法稍后在实例化期间解决)。

这并不意味着您应该始终以仅标头库为目标。尽管它们很好,但它们应该保留给模板和内联代码。它们不应该包括大量复杂的计算。

于 2014-09-08T19:34:51.387 回答