包含在头文件与前向声明中,并包含在.cpp中

时间:2013-04-05 07:12:02

标签: c++ header-files

我有一个B级,我想把成员称为A类。所以:

1

//A.h    
class B; 
class A 
{ 
private:
    B* m_p; 
}; 

//a.cpp
#include "B.h"

2

// A.h
#include "B.h"

class A 
{ 
private: 
    B * impl_; 
}; 

哪种方式更好,当一个没有太多依赖的小项目涉及时,这两个是相似的吗?

6 个答案:

答案 0 :(得分:31)

您执行此操作的第一种方式意味着在a.h中,class B存在是已知的,而不是定义。这限制了您在B内使用a.h可以执行的操作。例如,您可以使用B *类型的变量,但不能使用B类型的变量(因为对于类型为B的变量的声明,编译器必须能够看到完整定义B)。此外,如果您有B *类型的变量,则无法取消引用指针(因为也必须知道B的定义)。

因此,您的第二选择 - 没有这些问题 - 是首选,这是大多数人在大多数时间使用的。

只有第一种方法可能有用的特殊情况。例如:

  • 如果.h文件包含彼此(但是您可能会遇到一些其他问题,也可能涉及包含警示;这通常很难并且应该避免); < / LI>
  • 如果b.h非常庞大且复杂,那么您希望尽可能避免将其包含在内,因为它会降低编译过程的速度。

答案 1 :(得分:16)

您的第一种方法是前瞻性声明。你的第二个实际上包括B类。

何时使用其中一个?

在以下时间使用第一个:

  • 在A的定义中,您只有一个指向B的指针,即不是B的成员。
  • 你永远不会从A的定义中调用B的任何函数。(即对B的成员函数的所有调用都发生在实际实现A成员函数的.cpp文件中。)
  • 你希望B类的接口或大小经常改变,但不是A的接口。这样一来,如果B改变了,只有a.cpp的内容得到重新编译,但是啊(和其他包含啊的文件)不需要改变。

在以下时间使用第二个:

  • 您需要知道B的 size 。编译器使用其类定义及其所有成员的大小来计算类的大小。例如,如果类A具有类型B的成员,那么为了计算A的大小,编译器需要知道B的大小;要知道B的大小,你需要包含b.h.
    • 你需要调用B类的函数。为了知道你是否正在调用实际存在的函数,编译器需要知道B类的接口,即你需要包含b.h。

答案 2 :(得分:11)

答案: 1
看看http://www.umich.edu/~eecs381/handouts/handouts.html

C Header File Guidelines

C++ Header File Guidelines(密歇根大学EECS部门David Kieras)说:

  

准则#10。 如果类型X的声明不完整,请使用   它不是#including其标题X.h 。如果是另一个结构或类   类型X仅在内容中显示为指针或引用类型   一个标题文件,那么你不应该#include X.h,而只是放置一个   不完整的X声明(也称为“前进”声明)附近   标题文件的开头,如:class X;请参阅讲义   Incomplete Declarations有关这个强大的和更多的讨论   宝贵的技术。请注意,标准库包含标头   不完整的声明通常会对<iostream>产生影响   库,名为<iosfwd>。尽可能#include <iosfwd>,因为   <iostream>标题文件非常大(巨型模板!)。

答案 3 :(得分:0)

只需在班级A的标题中声明该课程。

class B;

答案 4 :(得分:0)

第二个更好。它使B类成为您使用.h文件包含的模块。考虑将来继承B的情况,并更新A以使用C。在第二种情况下,您只需替换标题#includeA的化妆。在第一种情况下,您必须更改前向声明。此外,在第二种情况下,您定义的不仅仅是符号B

如同评论中一样,如果头文件与其余代码位于同一目录中,则应使用#include "B.h"

答案 5 :(得分:0)

你正在做的事情被称为前向解除,你想要的原因就是如果你有类似A的东西使用B类而ALSO B类使用A类。

如果只有一种关系,你当然可以使用你的第二选择。 如果你需要双重用法,那么至少你的一个类别的declerations将不得不使用前进的decleration