是否有软件/工具可以查看编译C ++应用程序后包含头文件的顺序?我发现自己经常遇到循环依赖问题并看到“未定义的引用”错误消息:(
更新#1
我熟悉标题包括警卫,我正在使用它们,但由于某种原因,我仍然遇到循环依赖问题。
在我的情况下,我有很多情况, A类使用 B类,反之亦然。在这些情况下,我在 A.h 的顶部使用前向声明,例如“ B类; ”,反之亦然。
我是否需要在 A.h 的顶部做“ #include”B.h“”?或者“ B类; ”在 A.h 的顶部是否足够?
更新#2
您好,下面是我编译/链接时遇到问题的代码片段。下面有3个类:
A.cpp
#include "A.h"
namespace sef
{
A::A() {
// TODO Auto-generated constructor stub
b = 0;
}
A::~A() {
// TODO Auto-generated destructor stub
}
bool A::execute()
{
C::connectAndSaveFile();
b->start();
return true;
}
}
A.H
#ifndef A_H_
#define A_H_
//#include "B.h"
class B;
#include "C.h"
namespace sef {
class A {
public:
B* b;
bool execute();
A();
virtual ~A();
};
}
#endif /* A_H_ */
B.cpp
#include "B.h"
B::B() {
// TODO Auto-generated constructor stub
engine = 0;
bool result = engine->execute();
cout << result << endl;
}
B::~B() {
// TODO Auto-generated destructor stub
}
void B::start()
{
cout << "B::start()" << endl;
}
B.h
#ifndef B_H_
#define B_H_
#include <iostream>
#include <string>
using namespace std;
//#include "A.h"
namespace sef {
class A;
}
class B
{
public:
sef::A* engine;
B();
virtual ~B();
void start();
};
#endif /* B_H_ */
C.cpp
#include "C.h"
C::C() {
// TODO Auto-generated constructor stub
}
C::~C() {
// TODO Auto-generated destructor stub
}
void C::connectAndSaveFile()
{
cout << "C::connectAndSaveFile()" << endl;
}
C.h
#ifndef C_H_
#define C_H_
#include <iostream>
#include <string>
using namespace std;
class C {
public:
C();
virtual ~C();
static void connectAndSaveFile();
};
#endif /* C_H_ */
我似乎得到了错误:
***g++ -O0 -g3 -Wall -c -fmessage-length=0 -o "src\\A.o" "..\\src\\A.cpp"
..\src\A.cpp: In member function 'bool sef::A::execute()':
..\src\A.cpp:23:4: error: invalid use of incomplete type 'class B'
In file included from ..\src\A.cpp:7:0:
..\src\A.h:12:7: error: forward declaration of 'class B'***
答案 0 :(得分:2)
您的前向声明是一个良好的开端,但此外,A.cpp将需要包括B.h和C.h,因为它取消引用B*
并在C
中调用静态函数。同样,B.cpp需要A.h,因为它取消引用A*
。可能还有其他问题,但这应该让你走上正轨。
长话短说,class A
的前向声明只告诉编译器A
是类的名称。这足以让您在说出A*
或A&
(或其他几件事)时知道您的意思,但如果您想在A
上实际调用函数,或访问成员变量,或按值返回/取A
,或者使用A
1 类型的变量,您需要A
的完整定义从它的标题。
1 基本上,任何需要编译器知道sizeof(A)
或其成员/祖先信息的操作。
此外,这不是您的问题,但此代码将为您提供未定义的行为:
B::B() {
// TODO Auto-generated constructor stub
engine = 0;
bool result = engine->execute();
cout << result << endl;
}
您有效地将engine
设置为null,然后在其上调用函数。
除了最初的主题之外,通常认为头文件中的using namespace std
是不好的做法,因为包含它的每个人都将被迫使用该命名空间,无论他们是否愿意。