前瞻性声明的缺点是什么?

问题描述 投票:3回答:5

我想知道在可能的情况下在所有地方使用前向声明是否有任何缺点。这是我的标题只包含声明。

据我所知,使用前向声明可加快编译时间,但我不知道有什么缺点。

例:

啊:

Class A
{
};

b.h:

// Should I use and include "a.h" in the cpp file (e.g., a.cpp)
Class A;
Class B
{
    doSomething(A *a);
    A *myA;
};

或者它是否更好用

b.h:

#include "a.h"

Class B
{
    doSomething(A *a);
    A *myA;
};
c++ forward-declaration
5个回答
10
投票

使用前向声明可以改善解耦。如果你可以通过使用前向声明来避免包括"A.h",那么使用前向声明是个好主意。最好不仅因为你的构建运行得更快(毕竟,预处理的头文件可以很好地处理编译器的效率),但是因为它告诉读者你的声明你的类B的结构不依赖于你对类的了解A除了存在之外*。

编辑(回答你的问题)我知道转发声明的唯一缺点是你不能在所有情况下使用它们:例如,类似于这样的声明:

class B
{
    A myA[10];
};

不会编译,因为编译器需要知道A的大小。但是,编译器可以非常可靠地发现这些问题,并以明确的方式通知您。

*类B的实现很可能取决于知道类A的细节。但是,这种依赖关系变成了隐藏在你班级用户身上的B的实现细节;您可以随时更改它,而不会破坏依赖于类B的代码。


2
投票

使用前向声明可加快编译时间

这是部分正确的,因为编译器(和预处理器)不需要在包含此标头的每个文件中解析包含的标头。

更改标题并需要重新编译时看到的真正改进。

前向声明是打破循环包含的唯一方法。


1
投票

我会用实际的话说。优点:

  1. 避免循环编译器依赖性。除非你把A和B放在同一个标​​题中,否则你编写上面代码的方式甚至都不会编译。
  2. 它避免了编译时依赖性。您可以在不重新编译包含b.h的单元的情况下更改a.h.出于同样的原因,它通常可以加快构建速度。要了解有关此主题的更多信息,我建议查找Pimpl习语。

缺点:

  1. 以上面这种方式大量应用,您的一般源文件可能需要包含更多标题(我们无法通过包含B.h来实例化或使用A)。对我而言,这对于更快的构建来说是一次有价值的交流。
  2. 这可能是最大的骗局,它可能会带来一些运行时开销,具体取决于您正在做什么。在您给出的示例中,B不能直接将A存储为值。它涉及一个间接级别,如果B是A的内存管理器(对于pimpl也是如此),这也可能意味着额外的堆分配/释放。这种开销是否微不足道是您必须绘制线条的地方,值得记住的是,可维护性和开发人员的工作效率肯定比微观优化更重要,而微优化对用户来说甚至都不会引起注意。我不会用这个作为排除这种做法的理由,除非它肯定被证明是瓶颈或你事先知道堆分配/释放或指针间接的成本将是一个非平凡的开销。

1
投票

前向声明是打破循环包含的唯一方法。

我认为,如果不小心使用,这是主要的缺点。我在一个大型项目中工作,尽可能做出前瞻性声明。循环依赖最终是一个真正的问题。


0
投票

想到的唯一缺点是前向声明需要指针。因此,它们可能未初始化,因此可能导致空引用异常。作为我目前使用的编码标准,要求所有指针都需要空引用检查是否可以添加分配代码。我开始用Design By Contract不变量来解决这个问题;然后我可以断言在构造函数中初始化的任何东西都不会为null。

© www.soinside.com 2019 - 2024. All rights reserved.