c++ - 谷歌风格指南(前向声明部分)
问题描述
前言
谷歌风格指南包括前向声明的缺点列表
前向声明可以隐藏依赖关系,允许用户代码在标头更改时跳过必要的重新编译。
对库的后续更改可能会破坏前向声明。函数和模板的前向声明可以防止标头所有者对其 API 进行其他兼容的更改,例如扩大参数类型、添加具有默认值的模板参数或迁移到新的命名空间。
从命名空间 std:: 前向声明符号会产生未定义的行为。
可能很难确定是否需要前向声明或完整的#include。用前向声明替换 #include 可以默默地改变代码的含义:
代码:
// 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*)
如果#include 被替换为B 和D 的前向decls,test() 将调用f(void*)。
从标头前向声明多个符号可能比简单地#includeing 标头更冗长。
构造代码以启用前向声明(例如,使用指针成员而不是对象成员)会使代码变得更慢和更复杂。
问题
我对第一点特别感兴趣,因为我无法想出一个场景,即当 headers 更改时,前向 decleration 会跳过必要的重新编译。谁能告诉我这是怎么发生的?或者这是谷歌代码库固有的东西?
由于这是列表中的第一点,因此它似乎也相当重要。
解决方案
我无法想出一个单一的场景,即前向声明会在标题更改时跳过必要的重新编译。
我认为这也有点不清楚,也许可以更清楚一点。
隐藏依赖项意味着什么?
假设您的文件main.cc
需要header.h
正确构建。
如果
main.cc
包括header.h
,那么这是一个直接的依赖。如果
main.cc
包含lib.h
,然后lib.h
包含header.h
,那么这是一个间接依赖。如果
main.cc
以某种方式依赖lib.h
但如果不包含但不生成构建错误lib.h
,那么我可能会称其为隐藏依赖项。
然而,我不认为隐藏这个词是一个常见的术语,所以我同意这个措辞可以被改进或扩展。
这是怎么发生的?
我有main.c
,lib.h
和types.h
.
这里是main.c
:
#include "lib.h"
void test(D* x) { f(x); }
这里是lib.h
:
#include "types.h"
void f(B*);
void f(void*);
这里是types.h
:
struct B {};
struct D : B {};
现在,main.cc
依靠types.h
才能生成正确的代码。但是,main.cc
它只对 有直接依赖lib.h
,对 有隐藏依赖types.h
。如果我在中使用前向声明lib.h
,那么这会中断main.cc
。但main.cc
仍然编译!
中断的原因main.cc
是因为它不包含types.h
,即使main.cc
取决于types.h
. 前向声明使这成为可能。
推荐阅读
- python - 由于重力和碰撞,pygame中的爬梯不起作用
- java - 为什么数据类型“int”在以下代码中被括在括号中
- azure - 如何在 Azure 存储队列的开头插入消息?
- python - 有什么方法可以让我使用列表推导从列表中创建集合?
- python - 由于焦点在前一帧的输入,Tkinter 绑定方法不起作用
- azure - 列出和分组多个分支的构建 ID
- python - 当单词包含在另一列中时从一列打印
- node.js - 如何使用 find $or 查询返回用于查找文档的任何字段?
- java - 单击列表项时 ViewPager 变为空白
- angular - 减速器,实体适配器:类型上不存在属性“帐户” - Angular 7、Rxjs 6、Ngrx