【问题标题】:OOP C++ - Error as A.h includes B.h which includes A.h againOOP C++ - 错误,因为 A.h 包含 B.h,B.h 再次包含 A.h
【发布时间】:2013-02-15 01:28:34
【问题描述】:

我正在学习 OOP 并且有疑问。假设我有一个包含 ClassB.h 的文件 ClassA.h,并且在某些时候我的 ClassB.h 需要包含 ClassA .h

这会产生一个错误,我想我明白为什么会发生这种情况,因为我得到了一个无限的包含循环。但是在这种情况下该怎么办?有没有办法解决这个错误?或者我应该重新考虑我的课程以避免它?这是否意味着我的班级组织设计不佳?如果是这样,有什么方法可以安排我的“类图”并避免这种情况?

我只是想知道在这种情况下最佳做法是什么。另外,为什么“#pragma once”指令不能解决这个问题?提前致谢。

【问题讨论】:

  • 它应该有一个连字符来分隔标题,我现在补充一下,很抱歉造成混乱。
  • 通常习惯上包含导致问题的实际代码的代码 sn-p。它可以是您编写的测试用例,只是为了在此处发布,只要它确实存在您要询问的问题并且您已经对其进行了测试以确保它。原因是很难对这样的问题给出一个好的具体答案。

标签: c++ oop header include


【解决方案1】:

您也可以通过使用前向声明来解决这个问题。如果您没有创建包含在标头中的类的实际对象或不从它继承,例如,如果您只需要标头中的指针,则可以这样做。

例子:

ClassA.h
class ClassB;
//rest of the codes here

ClassB.h
class ClassA;
//rest of the codes here

ClassA.cpp
#include ClassA.h
#include ClassB.h

ClassB.cpp
#include ClassB.h
#inlcude ClassA.h

【讨论】:

    【解决方案2】:

    有一种方法可以修复它,但这也意味着你的班级组织被破坏了。

    修复它的方法称为“包含保护”,尽管许多编译器也支持#pragma once 指令。我想它不起作用,因为#pragma once 可能在解析整个内容之前不会考虑包含头文件。而且由于递归包含发生在头文件的中间,它还没有被解析完。

    包含守卫是这样的:

    在 ClassA.h 中:

    #pragma once // Just because. It really should help.
    #ifndef INCLUDED_CLASSA_H
    #define INCLUDED_CLASSA_H
    
    #include "ClassB.h"
    
    //... rest of header file
    
    #endif
    

    在 ClassB.h 中:

    #pragma once // Just because. It really should help.
    #ifndef INCLUDED_CLASSB_H
    #define INCLUDED_CLASSB_H
    
    #include "ClassA.h"
    
    //... rest of header file
    
    #endif
    

    组织问题称为循环依赖,循环依赖通常是个坏主意。有许多不同的方法可以打破它们,但使用哪种方法取决于依赖的确切性质和最初的原因。

    根据问题,您可以使用多种技术之一:

    • 从公共基类继承
    • 将两个类中的一个转换为另一个的基类- 这是前一个的变体。
    • 前向声明 - 这不是那么理想,因为它并没有真正破坏循环依赖,它只是安排它,因此您不需要还有一个有问题的循环包含依赖。
    • 将两个类的某些部分转换为它们都可以使用的类- 这是通用基类的另一种变体,它使用组合而不是继承。

    还有其他技术。事实上,有一本书在各种情况下使用了非常广泛的技术,因为消除循环依赖是这本书的一个重要主题。那本书是"Large-Scale C++ Software Design" by John Lakos

    【讨论】:

    • 所以#ifndef 守卫的工作方式与#pragma once 不同?无论如何,我只是测试了它并遇到了同样的问题。如果这是不好的做法,我会尝试重新安排事情来解决这个问题。
    • @LeandroNogueiraCouto:这些应该有效。你得到的错误究竟是什么?是的,这是不好的做法。 :-) 它们的工作方式不同,因为#pragma once 是由编译器在预处理器中以供应商认为合适的任何方式实现的(因为它只是一个广泛支持的扩展)。而那些 #ifdef 守卫依赖于明确指定的功能。
    • 我收到大量错误,超过 100 个,奇怪的语法错误和“未声明的标识符”。知道问题的名称有很大帮助,我搜索了循环依赖项,发现一个简单的前向声明对我的特定情况有帮助,以及涉及重构我的类的其他解决方案。
    • 顺便说一句,非常感谢您提供详细的答案并提及可能的解决方法!很有帮助。
    • @LeandroNogueiraCouto:如果您必须使用前向声明来处理另一个头文件中的类的循环依赖问题,这表明您可能应该重新考虑这一点。通常,它们最好用于处理单个头文件中的循环依赖。这通常不是最好的情况,但有时是个好主意。头文件之间的循环依赖几乎不是一个好主意。并且模块之间的循环依赖应该被认为是被禁止的。而且,不客气。这就是我们来这里的目的。 :-)
    【解决方案3】:

    在我过去的经验中,我通过使用继承解决了同样的问题。

    我解决的方法是 . ClassA -> ClassB : ClassB 被 ClassA 继承。 ClassA 有 ClassB 和 ClassA 想要的共同需求。

    然后我解决了“递归包含问题”

    【讨论】:

    • #include 与继承无关的问题 - 例如,您可能会遇到与 C 中的 #include 完全相同的问题,它不支持继承。
    猜你喜欢
    • 2021-05-03
    • 1970-01-01
    • 2013-10-22
    • 1970-01-01
    • 2012-07-08
    • 2014-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多