我有一个小型二叉树程序,分布在 4 个文件中:main.cpp、tree.h、loop.h 和 node.h。
在 main.cpp 文件中,我包含 loop.h,在 loop.h 中,我包含 arbol.h,在 arbol.h 中,我包含 node.h
我刚刚在我的 loop.h 文件的 Loop 类中创建了一个小函数,它是 windows.h 库中 Sleep 函数的简单副本。我想在 Tree 类的一个成员函数中使用这个函数,它在屏幕上打印树的节点,也就是说,我希望每次在屏幕上打印一个节点时等待 x 秒。
当我想在 Tree 类中创建 Loop 类对象或当我想使用继承时,会出现错误,编译器会生成错误“Loop 并不意味着类型”。到目前为止,我已经尝试过简单的继承、友元类和友元方法。我还从循环类中删除了该函数,并在 Tree 类中声明它以测试其正确操作。
我不包括 node.h 文件的详细信息,因为它只是一个具有 Node 结构的类。
循环.h 文件
#ifndef LOOP_H
#define LOOP_H
#include<iostream>
using namespace std;
#include "arbol.h"
#include<time.h>
class Loop{
private:
Arbol Kyou; /*
Se crea un bojeto derivado de la clase Árbol,
este objeto lo utilizo para ejecutar las funciones
de la clase Arbol (como lo es crear un nuevo
nodo, buscar nodo, etc) dentro de mis funciones de
la clase Loop (como lo es pedir los datos del nodo,
etc)
E.g. void pedirDatos(){
cout << "Dame numero: ";
cin >> n;
Kyou.CrearNodo(n);
}
*/
public:
void esperar(float segundos){...}
/* Más funciones que no son importantes para el problema */
};
#endif
文件树.h
#ifndef ARBOL_H
#define ARBOL_H
#include "nodo.h"
#include "loop.h" /* Incluyo el archivo loop.h */
class Arbol{
private:
Nodo* Raiz;
int contador = 0;
Loop mano; /* El error es este */
public:
void MostrarArbol(){
mano.esperar(0.5); /* La función es de la clase Loop */
/* El proceso recursivo para mostrar el árbol */
}
};
#endif
main.cpp 文件
#include<iostream>
using namespace std;
#include "loop.h"
int main(){
Loop l;
l.loop(); /* Función miembro de la clase Loop que genera todo el programa */
return 0;
}
使用 c++ 编程时可能面临的最常见问题之一是交叉引用。在您的情况下,标题
Loop
调用标题,Arbol
反之亦然。发生的情况如下。这个:
它变成了这样:
请注意,现在,在 内部
Arbol
,有一个对自身的引用。扩展包含不会再次导入 Tree,因为这就是警卫的用途#ifndef
。然后发生的事情是,在该文件中,声明
Loop
试图使用 classArbol
,这仍然是未知的,因为它是稍后声明的,因此是错误的。该问题的解决方法称为前向声明,它仅基于告诉编译器:“看,有一个类(或结构或枚举或函数)是这样调用的,我以后会告诉你更多细节” . 有了这些信息,编译器现在就可以编译了,尽管有一些限制,正如我们稍后会看到的,我们将把后者留到以后。
案例,你如何使用声明转发?
就这么简单:
它有什么限制?
由于编译器不知道类的大小,所以不能按值使用。指针只能声明:
由于编译器也不知道此类实现的函数,因此不可能调用成员函数,当然也不能调用
new
ordelete
,因为它们最终会分别调用构造函数和析构函数:而且,最重要的是,由于编译器也不知道类的继承树,c++ casts (
dynamic_cast
) 也会导致问题。为了使用所有这些功能,编译器必须知道类,而这只能通过相应的
#include
. 由于我们已经看到我们无法在头文件中添加依赖项,因此唯一的解决方案是将 移动#include
到实现文件中。实现文件通常不包含对其他实现文件的引用,因此这些文件中永远不会出现循环引用。注意:此时,您对线程中其他问题的问题如下:
通过添加
#include
您正在加载#define LOOP_H
,然后在实现文件中#include "loop.h" no se carga nada porque lo impiden las guardas (
再次调用#ifdef 时,LOOP_H` 检测到该符号已定义)。#include
通过从头文件中删除一个错误可以解决您的错误:该错误是因为您在声明类型之前尝试使用它。
根据
#include
编译器看到的声明顺序是:从
#include
字面上看是从这一点开始放这个文件的。在编译器知道其类型之前Loop
,您在tree.h文件中使用类。您可能认为您包含
loop.h
在 中,但它的内容在一开始arbol.h
就受到了保护。#ifndef LOOP_H
在main.h
中,通过在其中包含它,您定义了该符号,因此后续包含什么也不做(逻辑上的事情,或者您将有一个包含循环**.您的代码抛出的另一个错误: Class
Arbol
internal uses a classLoop
, internal uses a classArbol
, internal uses a classLoop
,......它还没有显示给你,因为它抱怨缺少一个类型,但它会。要弄清楚这一切,您必须预先声明class
Loop
。在文件Arbol.h
中,您必须添加一行:这样,编译器就已经知道它
Loop
是一个类。要解决类定义中的循环,其中一个必须停止使用
instancias
另一个,并用指针或引用替换它们