C++ - 嵌套包含 - 避免“包含嵌套太深的错误”

Posted

技术标签:

【中文标题】C++ - 嵌套包含 - 避免“包含嵌套太深的错误”【英文标题】:C++ - Nested include - Avoiding 'include nested too deeply error' 【发布时间】:2011-05-16 18:30:29 【问题描述】:

如果我想在我的 C++ 代码中拥有以下连接,那么声明头文件的最佳方式是什么,以免出现 'include nested too deep 错误'

在我的边缘类中,我有一些需要返回 Node 对象的函数。 Edge 类也是如此,我有需要返回 Node 对象的函数。但是编译器不允许我有这个嵌套循环的东西。

Node.h

#ifndef _NODE_h__
#define __NODE_h__

#include "Edge.h" 
public:
    Node();
    ~Node();
    void setName(string);
    string getName();
    void addEdge(Edge*);
    vector<Edge* > getEdges()  return _edges; ;
;
#endif

Edge.h

#ifndef _EDGE_h__
#define __EDGE_h__

#include "Node.h"
class Edge 

public:

    Edge();
    Edge(bool);
    ~Edge();
    bool hasBeenSeen()  return _seen; ;
    void reset()  _seen = false; ;  // resets seen param to false
    Node* getSource()  return _source; ;
    Node* getTarget()  return _target; ;
    void setSource(Node* source)  _source = source; ;
    void setTarget(Node* target)  _target = target; ;
;
#endif

【问题讨论】:

一方面,你需要头部保护:***.com/questions/2979384/purpose-of-header-guards 我尝试使用 IFNDEF 和 DEFINE 宏,但仍然收到“包含嵌套太深错误”。 @all_by_grace:那我怀疑你没做对。但是你也会遇到循环依赖的问题。 不要使用带有__的名字;它们保留供实现使用。 我只是想指出你实际上是在使用守卫,但有一个小错误:#ifndef 语句中定义的宏应该与#defined 中的宏相同。跨度> 【参考方案1】:

正如其他人所建议的那样,使用标题保护。但也尝试向前声明有问题的类。您可能还必须在至少一个类中使用指针(而不是值),但如果没有看到代码,我们无法判断。

所以 edge.h 应该是这样的:

#ifndef EDGE_H
#define EDGE_H

class Node;    // forward declaration

Node functionB();

#endif

请注意,您必须在一个单独的 C++ 文件中定义您的函数,然后#includes "node.h"。

如果这一切看起来很复杂,那么您应该尝试简化您的设计。节点和边可能没有必要相互了解——单向依赖就足够了。

最后,包含双下划线的名称在 C++ 中是保留的——你不能在自己的代码中创建这样的名称。

【讨论】:

【参考方案2】:

Edge.h

#ifndef EDGE_H_INCLUDED
#define EDGE_H_INCLUDED

class Node;

class Edge

    int edge_num;
public:
    Edge(int i) : edge_num(i)  ;
    Node memberB();
;

#include "Node.h"  

Node Edge::memberB()  Node n(edge_num); return n; 
Node functionB()      Node n(2);        return n; 

#endif /* EDGE_H_INCLUDED */

节点.h

#ifndef NODE_H_INCLUDED
#define NODE_H_INCLUDED

class Edge;

class Node

    int node_num;
public:
    Node(int i) : node_num(i)  ;
    Edge memberA();
;

#include "Edge.h"

Edge Node::memberA()  Edge e(node_num); return e; 
Edge functionA()      Edge e(1);        return e; 

#endif /* NODE_H_INCLUDED */

请注意,我在包含其他标头之前已前向声明了类“Edge”和“Node”,因此在定义函数或成员函数时,它返回的类也已定义。

【讨论】:

【参考方案3】:

包含保护的问题在于它们不匹配!

您测试_SOMETHING(一个下划线),如果没有找到,则定义__SOMETHING(两个下划线);这两个应该匹配,否则包含保护不起作用!

正如其他人所指出的,避免使用下划线开头,因为它们是为库和操作系统保留的。

【讨论】:

我已经修复了问题中的代码 - 但在撰写本文时,观察结果是完全正确的。双下划线注释仍然适用;下划线和大写字母开头的名称也被保留。 @Jonathan 恕我直言,永远不要修复问题页面上的代码,因为这可能会导致部分海报和部分回答问题的人混淆。如果从一开始就“修复”了这个问题,那么没有人会发现这个错误。 我不同意五年前的自己;我已经回滚了我的编辑。【参考方案4】:

这可以通过使用 pragma 守卫或#pragma once(如果您的编译器支持后者)来防止。

要使用编译指示守卫,只需这样做:

#ifndef SOME_IDENTIFIER
#define SOME_IDENTIFIER

// ... code ...

#endif

确保为每个头文件更改SOME_IDENTIFIER。通常人们会这样做NAME_OF_HEADER_H;如果您更改一个,请确保更改标识符的两个实例。

此外,如果您这样做,请确保您所做的任何#includes pragma 守卫内。

如果你只想使用#pragma once 并且你的编译器支持它,你只需要添加

#pragma once

到头文件的顶部。

另一方面,请考虑将函数 functionAfunctionB 的定义移动到它们自己的 .cpp 文件中,并将原型保留在 .h 文件中,这样就不会出现链接器错误。

【讨论】:

我不认为包含守卫有助于循环引用。如果您指的是指针类型成员,它会起作用,但出于另一个原因。

以上是关于C++ - 嵌套包含 - 避免“包含嵌套太深的错误”的主要内容,如果未能解决你的问题,请参考以下文章

VST C++ 嵌套类 - 构造和包含

避免多个包含 C++

C++ 私有嵌套抽象类

浏览器返回作用于页面本身之前的嵌套 iframe - 有没有办法避免它?

python 和 ctypes 访问具有嵌套结构的 c++ 类

如何使用 Apollo 和 React Router 避免嵌套路由/查询组件的请求瀑布?