25

考虑以下两种情况(编辑只是为了完成整个问题并使其更清晰)

案例1:(没有按照下面正确的方式编译)

//B.h
#ifndef B_H
#define B_H
#include "B.h"

class A;

class B { 
        A obj;
        public:
        void printA_thruB();

         };  
#endif

//B.cpp
#include "B.h"
#include <iostream>

void B::printA_thruB(){
        obj.printA();
        }   


//A.h;
#ifndef A_H
#define A_H

#include "A.h"

class A { 
        int a;
        public:
        A();
        void printA();

         };  
#endif   

//A.cpp                           
#include "A.h"                    
#include <iostream>               

A::A(){                           
        a=10;                     
        }                         

void A::printA()                  
{                                 
std::cout<<"A:"<<a<<std::endl;    
}  


//main.cpp
 #include "B.h"
  #include<iostream>
 using namespace std;

 int main()
 {
 B obj;
 obj.printA_thruB();
 }

案例2:(唯一的修改......没有编译错误)

//B.h

#include "A.h" //Add this line
//class A;     //comment out this line

让我们假设 A.cpp 和 B.cpp 一起编译。以上两种情况有什么区别吗?是否有理由更喜欢一种方法而不是另一种?

编辑:那么我如何使方案 1 起作用。

4

6 回答 6

18

前向声明不能替代头文件包含。

顾名思义,前向声明只是一个Declaration 而不是一个定义

因此,您将声明编译器说它是一个类,而我只是在这里声明它,并将在何时使用它时为您提供定义。因此,通常您forward declare在 Header 文件和#include.cpp 文件中将使用前向声明类的成员。

通过这样做,你所做的是,无论你在哪里包含头文件,都只会有一个类的声明,而不是整个内容#included......

不过话说回来,当编译器需要定义类的时候,应该是#included..

所以,在你的情况下A obj;需要定义,class A因此你应该#include..

我自己在这里问了一个类似的问题,另一个 类似的问题也有一个很好的答案......

希望能帮助到你..

于 2010-09-03T05:18:57.447 回答
14

情况 1 在编译 B.cpp 时会产生“不完整类型”错误。因为 B 类包含 A 类对象,所以 A 类的定义(尤其是大小)需要在 B 类定义之前完成。

或者,您可以选择将 some_variable 设置为指向 A 类的指针或引用,在这种情况下,您的前向声明在 Bh 中就足够了。您仍然需要在 B.cpp 中完整定义 A(假设您实际使用了成员函数/数据)。

于 2010-09-03T03:15:41.737 回答
4

在您有相互引用的类的情况下,您需要使用前向声明。

//A.h

class B;

class A {
    B* someVar;
}

//B.h
#include <A.h>

class B {
    A* someVar;
}

但是在你提出的情况下这样做没有任何好处。

于 2010-09-03T03:19:35.527 回答
3

像编译器一样思考。为了创建一个A内部B,编译器必须知道如何构建一个A,而唯一的方法就是拥有完整的定义。前向声明告诉编译器类A存在而不描述它的样子;这足以定义指针或引用。当需要使用该指针或引用时,将需要完整的类定义。

于 2010-09-03T04:34:12.003 回答
2

如果您打算将 some_variable 描述为指针,那么经常推荐的做法是尽可能使用前向声明,以避免包含开销和更长的编译时间。

我完全支持最佳实践,但我真的很喜欢使用具有良好代码导航功能的 IDE,并且转发会导致出现问题,至少在 Netbeans 中是这样。每当我尝试导航到类型声明时,我总是以前进而不是包含实际声明的 .h 文件结束。为了便于导航,我愿意接受一些额外的编译时间。也许这只是 Netbeans 的一个问题 :)

..哦是的..如果您查看问题右侧的相关问题,您会发现许多关于前向声明的附加信息。

于 2010-09-03T03:24:44.637 回答
0

对于情况1,编译器会报B类的“不完整类型”,因为B类包含一个A类对象,而你没有告诉B类A的任何细节,所以编译器无法决定B对象的大小。

对于您的情况,您可以使用A& objorA* obj代替A obj,因为引用/指针的大小是 const(对于 32 位/64 位 CPU 为 4/8)。

于 2017-09-14T06:00:28.383 回答