我正在进行时钟显示任务,我的教授希望我们使用两个类,NumberDisplay和ClockDisplay。所以我总共有两个头文件和三个cpp文件。当我使用第一个类实现作业的第一部分时,一切都很好。我注意到我的教授要我们在ClockDisplay标题中声明一个NumberDisplay对象。我想只是声明像普通的那样工作NumberDisplay hours = NumberDisplay(24);
但是我无法访问信息,除非我为ClockDisplay.h包含NumberDisplay.h文件。当我这样做时,我假设我的错误是由于在#include <NumberDisplay.h>
和我的NumberDisplay.cpp
中都使用了ClockDisplay.cpp
。我只是想知道构造我的文件的正确方法,以便我可以在ClockDisplay头文件中正确创建NumberDisplay对象,然后在我的ClockDisplay cpp文件中使用所述对象。
答案 0 :(得分:0)
您可以在#include "NumberDisplay.h"
内ClockDisplay.h
。这将允许您在ClockDisplay的类声明中使用NumberDisplay对象。
作为旁注,请务必使用包含防护装置作为标题。这将防止在编译期间多次包含标头。使用#pragma once
或
#ifndef NUMBERDISPLAY_H_
#define NUMBERDISPLAY_H_
...
#endif // NUMBERDISPLAY_H_
答案 1 :(得分:0)
用户Sean Monroe指出使用header
或include guards
;这可能并不总是完整的答案。在许多情况下,这将有助于解决您当前的问题,但如果您不小心,您可能成为循环包含的受害者。
在我提及任何相关内容之前,我将简要介绍#include <someheader.h>
和#include "someheader.h"
之间的区别。第一个将通过使用默认情况下通过IDE设置的系统环境变量来查看大多数系统,操作系统,编译器和标准库文件的位置。后者将查看在当前项目的包含路径中设置的任何直接目录,其根路径是在Visual Studio中创建时创建代码所在的位置;其他IDE很可能会有所不同,但概念仍然相同。
圆形包括:有时单独使用头部防护装置是不够的。举个例子:
file a.h
#ifndef A_H
#define A_H
#include "b.h"
class A {
private:
B b;
public:
explicit A( const B& b ) { ... }
};
#endif
file b.h
#ifndef B_H
#define B_H
#include "A.h"
class B {
public:
explicit( A* pA ) { ... }
};
#endif
这将产生一个循环包含,这是非常重要的事情。无论您尝试在其他文件,命名空间,类或函数中创建对象的哪个类A
或B
,编译器都会尝试构造第一个类,并且为了这样做,它需要构造第二个类但是当试图构造第二个类来完成第一个类时,它会返回并尝试再次构造第一个类,因为下一个需要第一个类是一个不完整的对象,反之亦然。这并不是每个说明的循环包含但它是不完整类的依赖性的循环无限递归。您可以阅读此Q / A以获取更多信息:Resolve Circular Dependencies。
有时仅仅将一个类的适当头部包含在另一个类的头部中是不够的;有时您可能需要在类的标题中声明class prototype
或forward declaration
,然后在该类的cpp
文件中包含头文件。但这通常最常用于pointers
或references
但不是本地副本,因为pointers
和references
由内存中具有固定大小的内存位置寻址。例如:
file A.h
#ifndef A_H
#define A_H
class B;
class A {
private:
B* pB;
public:
explicit A( const B& b );
};
#endif
file A.cpp
#include "A.h"
#include "B.h"
A::A( const B& b ) { ... }
file B.h
#ifndef B_H
#define B_H
#include "A.h"
class B {
public:
B(){ ... }
/*param type*/ someFunc( A* pA ) { /* do something with pA */ }
};
问题比这里讨论的问题多,但你可以在我上面提供的同一链接的其他一些答案中阅读它们。