【问题标题】:How to fix a C++ cyclical dependency with forward declaration in template class header如何在模板类头中使用前向声明修复 C++ 循环依赖
【发布时间】:2018-12-05 19:41:40
【问题描述】:

在我的面向应用的对象课程中,出于教学目的,我们被要求在不使用 STL 或 cstring 中的任何字符串操作函数的情况下开发一个功能齐全的 C++ 应用程序(稍后将涉及用于 GUI 的 SDL)。

在重新开发简单的字符串和列表容器层次类时,我遇到了循环依赖问题。以前,我使用前向声明解决了这些问题。然而,这一次,事情并没有按预期进行,这个问题让我忙了几个晚上。

这是我遇到的问题的简单 UML 图。

每个类都有自己的.cpp.hpp 文件,除了BaseListItemNotFoundException 我在BaseList 类声明上方使用using 声明。

class BaseListItemNotFoundException: BaseException {
    using BaseException::BaseException;
};

即使这没有添加任何附加信息(恕我直言),让我准确地说 BaseListHeplList 类实际上是使用 .ipp.hpp 定义的模板类。

我省略了一些其他涉及的类,以将环境限制为一个最小的工作示例(迭代器和 Cell 通用类层次结构用作列表的有效负载)。为清楚起见,已删除使用 defineifndef 条件的标头保护。

以下是文件的片段:

BaseList.hpp:

#include <cstddef>
#include <iostream>
#include "Cell.hpp"

class HeplString; // Forward declaration

#include "BaseException.hpp"
class BaseListItemNotFoundException: BaseException {
    using BaseException::BaseException;
};

template<class T>
class BaseList {
    // code
};

HeplList.hpp:

#include <cstddef>
#include "BaseList.hpp"
#include "Cell.hpp"

template<class T>
class HeplList : public BaseList<T> {
    // code
};

#include "HeplList.ipp"

HeplString.hpp:

#include <cstddef>
#include <iostream>
#include <ostream>
#include <fstream>
#include "HeplList.hpp"

class HeplString {
    // code
};

BaseException.hpp:

#include "HeplString.hpp"
#include "BaseList.hpp"

class BaseException {
    // code
};

这个例子的主要问题是这样的错误:

src/tests/../BaseException.hpp:9:20: error: field ‘msg’ has incomplete type ‘HeplString’
         HeplString msg;
                    ^~~
In file included from src/tests/../HeplList.hpp:5,
                 from src/tests/../HeplString.hpp:9,
                 from src/tests/test.cpp:2:
src/tests/../BaseList.hpp:9:7: note: forward declaration of ‘class HeplString’
 class HeplString;
       ^~~~~~~~~~

我不明白我在这里做错了什么。阅读其他类似的问题并没有帮助。

如果需要,可以在这里找到我的 git 存储库以及完整代码:https://github.com/wget/hepl-2-cpp

【问题讨论】:

  • 为什么BaseException 需要了解BaseListHeplString
  • BaseException 在内部使用HeplString 来存储自定义错误消息。因此,BaseException 通过使用HeplString 隐式使用BaseList
  • 你似乎在这里绕了一圈。戒指必须在某处被打破。您永远不能仅使用前向声明创建数据成员,但您可以创建指向它的指针或引用。这意味着实例将不得不生活在其他地方。
  • @ravnsgaard 在提议的解决方案中我也看到了使用引用,但是对于当前的用例,我不知道如何以优雅的 OOP 方式实现它:-/
  • 您需要将声明和定义明确分开。 HeplString 声明只需要HeplList的前向声明; 定义需要HeplList的完整定义。

标签: c++ c++11 templates circular-dependency forward-declaration


【解决方案1】:
  • #include "BaseException.hpp" 添加到BaseList.hpp
  • #include "HeplList.hpp" 添加到HeplString.cpp
  • 将前向声明template&lt;class T&gt; class HeplList; 添加到HeplString.hpp
  • 现在,您可能需要修改一些不包括 BaseList.hpp 标头的其他类,因为它们依赖标头 HeplString.hpp 为它们执行此操作。

【讨论】:

猜你喜欢
  • 2019-03-09
  • 1970-01-01
  • 1970-01-01
  • 2012-10-08
  • 2020-07-08
  • 1970-01-01
  • 1970-01-01
  • 2012-04-24
  • 1970-01-01
相关资源
最近更新 更多