【问题标题】:Forward declaration VS compiling order error in c++ to avoid recursive header inclusionc++中的前向声明VS编译顺序错误,以避免递归头包含
【发布时间】:2013-01-30 10:58:08
【问题描述】:

我正在编写由大量 .h 和 .c 文件组成的 C++ 大型代码。

主要问题是由一对应该相互链接的类引起的。 由于软件架构中的声明需要,第一个类(命名为 A)在“上层”类中初始化。

所以我们得到了类似的东西:

#include A.h
class mainClass{
...
A a;
...
}

A.h 看起来像:

#ifndef A_H
#define A_H

#include B.h
class A{
A();
fooA();
...
private:
B b;
...   
}
#endif

A.cpp 看起来像:

#include B.h
#include A.h
...
A::A(){
...
b(this) //here I get the first error that follows
...
}
A::fooA(){//do somthing}

为了避免在第二个类中包含相互的头文件(让它成为 B),我使用了前向声明和指向 A 类的指针 var。

B.h 看起来像:

#ifndef B_H
#define B_H

class A; //Forward declaration to A
class B{
B()
B(A* const t)
fooB();
A* a;   //pointer to A object
}

B.cpp 看起来像:

#include B.h  

B::B(){
//default constructor. Do Nothing
}
B::B(A* const t){
  this->a=t //constructor that set the pointer to the object of type A
}

B::fooB(){
   a->fooA(); //here i get the second error that follows
}

现在,如果在我的 Makefile 中我在 B 之前链接 A,我得到编译错误:

//First error. See code above for line numbers
error: no match for call to ‘(B) (A* const)’

另一方面,如果我在 A 之前链接 B,我会得到编译错误:

//Second error. see code above for line numbers
error: invalid use of incomplete type ‘struct A’
_B.h:'line of the forward declaration': error: forward declaration of ‘struct A’

我必须承认我对 c++ 还很陌生,所以我不明白我错在哪里。

编辑

现在我正在使用解决方案:

  1. 使用包含防护
  2. 前向声明A类,B.h中不包含A.h
  3. 在 A.cpp 和 B.cpp 中同时包含 B.h 和 A.h。始终在 A.h 之前包含 B.h

但我得到同样的错误:

error: no match for call to ‘(B) (A* const)'

会不会是构造函数重载问题?如果我删除该行

b(this)

编译工作正常。

已解决

如果 a 使用帮助函数在 B 中设置变量 A* a,则使用构造函数在编译期间一切正常。也许我需要更好地理解 C++ 中的构造函数重载。非常感谢。

【问题讨论】:

  • 嗯,首先引起我注意的是:您的头文件缺少包括保护。 en.wikipedia.org/wiki/Include_guard
  • 我为这个错误道歉。所有头文件都包含保护...再次抱歉...我正在尝试简化两个类中的大量代码,但我忘记在上面的代码中编写包含保护。
  • 我编辑了帖子以更好地反映我的代码的真实状态。谢谢你的建议。

标签: c++ forward-declaration


【解决方案1】:

尝试在 B.cpp 中包含“A.h”!

当您需要使用 B.cpp 中的 A 时,这将解析您的“A”类型。只需确保您什么都不做,只在 B.h 中保留对 A 的指针/引用,并在 B.cpp 中对 A 进行所有实际工作。

【讨论】:

    【解决方案2】:

    首先 - 遵循“us2012”的想法并使用包含警卫!

    然后 - 更改前向声明:

    啊哈:

    #ifndef A_H
    #define A_H
    class B;
    class A{
       A();
       fooA();
       ...
    private:
       B b;
       ...   
    }
    #endif
    

    以及在 A.cpp 中包含 B.h

    在 B.h 中,您再次包含 A.h - 但包含防护应防止错误:

    #ifndef B_H
    #define B_H
    
    #include "A.h"
    class B{
      B()
      B(A* const t)
      fooB();
      A* a;   //pointer to A object
    }
    #endif
    

    我还没有测试过......但它应该可以工作。

    【讨论】:

    • 但是我相信如果 a 在 A.h 中使用对 B 的前向声明,我只能使用指向 B 对象的指针,并且我需要在 A 代码中初始化 B 对象。我错了吗?
    • 在标题中你只需要声明对象——你只需要知道 *.cpp 文件中的实现——在这种情况下,当第一次调用 A 的构造函数时。在 A.cpp 你可以导入 B.h!但正如我所见 - 你已经找到了解决方案!
    【解决方案3】:
    1. 使用包含防护
    2. 前向声明A类,B.h中不包含A.h
    3. 在 A.cpp 和 B.cpp 中同时包含 B.h 和 A.h。始终在 A.h 之前包含 B.h

    【讨论】:

    • 我尝试了这个解决方案,但我仍然收到“调用不匹配”错误。似乎编译器找不到构造函数定义。当然,我还将 B.h 包含在 A.h 中。
    • 你在写:A::A() { b(this); } ?它应该是: A::A() : b(this) { };我已经测试了你的代码,它适用于 mingw32-gcc 4.5.2
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-12
    • 2017-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多