嵌套类包含标头

Nested class include header

本文关键字:包含标 嵌套      更新时间:2023-10-16

我有一个类看起来像这样:

// List.hpp
template<typename T>
class List {
    ...
private:
    class Node;
};

我想把List<T>::Node的完整定义放在一个单独的文件中:

// Node.hpp
template<typename T>
class List<T>::Node {
    ...
};

我的问题是,我应该在每个文件中包含什么,以及将#include放在哪里?

最简单的方法(我认为)是在List.hpp的末尾包含Node.hpp,而不在Node.hpp中包含任何内容。然而,这使得Node.hpp本身并不是一个完整的文件(比如说,如果我在IDE或其他地方打开它,由于缺少List<T>的定义,会有很多错误)。此外,我不确定是否可以将#include放在文件的底部。

假设每个文件都有自己的包含保护#define,我也可以在Node.hpp的顶部包含List.hpp(让IDE高兴),然后在List.hpp的底部再次包含Node.hpp,但我不知道这是否是个好主意。

编译List<T>::Node的成员函数时,编译器始终需要模板类List的可见性。其结果是,任何需要Node.hpp的内容的可见性的编译单元都需要List.hpp的内容(模板化成员的定义)的可见性。

最简单的选项是将Node.hpp的内容放在List.hpp的末尾,并且仅将#include "List.h"放在需要任一模板的编译单元中。这完全消除了对Node.hpp的需要。

如果您真的必须同时拥有这两个标头(这对我来说似乎是任意的,毫无意义,因为List<T>::NodeList<T>的一个组件),那么一个选项是帮助包含保护。

  // List.hpp
  #ifndef LIST_HPP_INCLUDED   // some unique macro
  #define LIST_HPP_INCLUDED
  // definition of templated class List
  #include "Node.hpp"   // this must be after the definition of List<T>
  #endif

和Node.hpp

  // Node.hpp
  #ifndef NODE_HPP_INCLUDED   // some unique macro
  #define NODE_HPP_INCLUDED
  #include "List.hpp"     // this must precede the definitions for List<T>::Node
  // definition of templated class List<T>::Node
  #endif

这允许任何编译单元将任一标头设为#included,并且include保护停止无限递归include。

大多数现代IDE都能应付这种情况。如果你有一个没有,那么简单地转换到一个单独的头文件。