Preface
Google 风格指南列出了前向声明的缺点
-
前向声明可以隐藏依赖项,允许用户代码在标头更改时跳过必要的重新编译。
-
前向声明可能会因库的后续更改而被破坏。函数和模板的前向声明可以防止标头所有者对其 API 进行其他兼容的更改,例如扩大参数类型、添加具有默认值的模板参数或迁移到新的命名空间。
-
从命名空间 std:: 前向声明符号会产生未定义的行为。
-
确定是否需要前向声明或完整的 #include 可能很困难。用前向声明替换 #include 可以默默地改变代码的含义:
Code:
// b.h:
struct B {};
struct D : B {};
// good_user.cc:
#include "b.h"
void f(B*);
void f(void*);
void test(D* x) { f(x); } // calls f(B*)
如果 B 和 D 的#include 被替换为前向声明,test() 将调用 f(void*)。
-
从标头中向前声明多个符号可能比简单地#includeing 标头更详细。
-
构建代码以启用前向声明(例如使用指针成员而不是对象成员)可能会使代码更慢、更复杂。
Question
我对第一点特别感兴趣,因为我无法想出一个单一的场景,其中前瞻性声明将当标头更改时跳过必要的重新编译。谁能告诉我这是怎么发生的?或者这是谷歌代码库固有的东西?
由于这是列表中的第一点,因此它似乎也相当重要。
我无法想出一个单一的场景,其中前瞻性声明会当标头更改时跳过必要的重新编译。
我认为这也有点不清楚,也许可以说得更清楚一些。
依赖关系意味着什么hidden?
假设你的文件main.cc
needs header.h
以便正确构建。
If main.cc
包括header.h
,那么这是一个direct依赖性。
If main.cc
包括lib.h
, 进而lib.h
包括header.h
,那么这是一个indirect依赖性。
If main.cc
某种程度上取决于lib.h
但如果出现以下情况,则不会生成构建错误lib.h
不包括在内,那么我可以称之为hidden依赖性。
我不认为这个词hidden然而,这是一个常见的术语,所以我同意可以对措辞进行细化或扩展。
这是怎么发生的?
I have main.c
, lib.h
, and types.h
.
Here is main.c
:
#include "lib.h"
void test(D* x) { f(x); }
Here is lib.h
:
#include "types.h"
void f(B*);
void f(void*);
Here is types.h
:
struct B {};
struct D : B {};
Now, main.cc
依赖于取决于types.h
以便生成正确的代码。然而,main.cc
仅直接依赖于lib.h
, 它有一个hidden依赖于types.h
。如果我在中使用前向声明lib.h
,那么这就打破了main.cc
。但是main.cc
仍然可以编译!
而原因是main.cc
休息是因为它不包括types.h
, 虽然main.cc
取决于声明types.h
。前向声明使这成为可能。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)