【问题标题】:Why am I suffering Circular Dependency here?为什么我在这里遭受循环依赖?
【发布时间】:2016-12-06 09:05:21
【问题描述】:

实用程序.h

#ifndef _UTILITIES_
#define _UTILITIES_

#include "MyFirstCairoPlugin.h"

class PLUG_CLASS_NAME;

class Utilities
{
private:
    PLUG_CLASS_NAME *pPlug;

public:
    Utilities(PLUG_CLASS_NAME *plug);
    ~Utilities();
};

#endif // !_UTILITIES_

实用程序.cpp

#include "Utilities.h"

Utilities::Utilities(PLUG_CLASS_NAME *plug) : pPlug(plug) {
    IColor color = IColor(100, 100, 100, 255);
}
Utilities::~Utilities() {

}

这就是我遇到麻烦的地方,使用来自MyFirstCairoPlugin.h的这个类:

#ifndef _MYFIRSTCAIROPLUGIN_
#define _MYFIRSTCAIROPLUGIN_

#include "IPlug_include_in_plug_hdr.h"
#include "resource.h"

#include "Utilities.h"

//class Utilities;

class MyFirstCairoPlugin : public IPlug
{
private:

public:
    Utilities *pUtilities;

    MyFirstCairoPlugin(IPlugInstanceInfo instanceInfo);
    ~MyFirstCairoPlugin();
};

#endif // !_MYFIRSTCAIROPLUGIN_

如果我不取消注释//class Utilities;(前向声明),它就不能使用实用程序(即使我已经在上面包含了它,#include "Utilities.h")。它给了我“典型的”循环依赖错误`:

syntax error: missing ';' before '*' (compiling source file ..\..\..\IPlug_AddOns\Utilities.cpp)

我哪里错了?

【问题讨论】:

  • 为什么utilities.h 需要#include "MyFirstCairoPlugin.h"
  • 因为PLUG_CLASS_NAME是一个宏,并且“定义”了MyFirstCairoPlugin类的名字,在MyFirstCairoPlugin.h里面
  • MyFirstCairoPlugin.h 不需要包含utilities.h 如果你转发声明Utilities
  • 你已经消除了类之间的循环依赖,但是你仍然有头之间的循环依赖。
  • @paizza 由于 molbdnilo 在上述评论中所说的话。这就是你打破依赖的方式。

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


【解决方案1】:

Utilities.h 包含 MyFirstCairoPlugin.h,MyFirstCairoPlugin.h 包含 Utilities.h,即一个圈,逻辑上产生圈依赖。

你应该这样做:

如果一个类在声明中需要另一个类,或者如果它显然是它最重要的部分,请包含它。示例:“图像”类可能包含“颜色”类 如果一个类在某种程度上使用了另一个类,例如将其存储在指针中或在调用某些方法时使用它,请使用前向声明。 如果它根本不需要其他类,那么它也不需要。 对于第二种情况,实现文件将包含依赖类。

在您的情况下,MyFirstCairoPlugin 存储一个指向实用程序的指针,因此它应该执行实用程序的前向声明,但不包括它。顺便说一句,那个指针不应该是公开的。

它应该是这样的:

#ifndef _MYFIRSTCAIROPLUGIN_
#define _MYFIRSTCAIROPLUGIN_

#include "IPlug_include_in_plug_hdr.h" //<--- no idea what that is about
#include "resource.h"

class Utilities;

class MyFirstCairoPlugin : public IPlug
{
private:

public:
    Utilities* pUtilities; //<-- shouldn't be public, you should always use encapsulation 
...

另一方面,Utilities 甚至不使用 MyFirstCairoPlugin,所以这里有第三种情况。你为什么首先让它包含 MyFirstCairoPlugin?如果那个宏可能是 MyFirstCairoPlugin,那么没问题,它已经有一个前向声明。不过,不会在宏上这样做。而是将 Utilities 作为模板类。顺便说一句,“实用程序”是一个相当宽泛的名称,听起来很容易导致名称冲突。

可能是这样的:

#ifndef _UTILITIES_
#define _UTILITIES_

template<class T>
class Utilities
{
private:
    T* pPlug;

public:
    Utilities(T* plug);
...

编辑:您似乎对模板不满意,这是另一种可能性:

创建一个抽象类(/接口),MyFirstCairoPlugin 将是其子类,提供实用程序实现中所需的所有方法。假设它被称为“插件”。好像你已经有这样的类了,但由于我不知道 IPlug 是什么,所以我用另一个名字。

围绕插件而不是 MyFirstCairoPlugin 或 PLUG_CLASS_NAME 构建实用程序。然后简单地给它一个 MyFirstCairoPlugin 的实例,它就是一个有效的 Plugin 实例。只要Plugin的方法是抽象的和虚的,在Plugin的指针上调用方法就会调用MyFirstCairoPlugin的方法,大家都很开心。

【讨论】:

  • 我在 Utilities 中包含 MyFirstCairoPlugin,因为 PLUG_CLASS_NAME 它是一个“定义”类 MyFirstCairoPlugin 名称的宏,它位于 MyFirstCairoPlugin.h 中。
  • @paizza 这听起来像是一个非常奇怪的依赖结构。不要那样做。如果我在不知情的情况下看到你的课程,我不知道你在哪里定义了那个宏。永远不会猜到使用它的类会这样做。不必要地增加了耦合。对我的帖子进行了编辑,使用模板解决方案。
  • 我会试一试,但我在使用模板 stackoverflow.com/questions/40993286/… 拆分 .h 和 .cpp 时遇到了一些麻烦
  • 如果你使用头文件和 cpp 文件,这个解决方案管理起来很糟糕:(
  • 嗯?您只需在 cpp 文件中为每个方法添加一行模板参数即可。非常常见,易于阅读。没看到问题。如果您希望能够一直切换您的插件类,那么您需要一个模板。也就是说,您可以做的另一件事是创建一个抽象类“插件”,围绕该类构建实用程序(尤其是因为无论如何您都使用指针),然后使 MyFirstCairoPlugin 成为插件的子类。因为它实际上似乎是现在。如果可行,则取决于您的实施。
【解决方案2】:

看看它是如何一步一步包含进来的:

  • 在 Utilities.cpp 中,您包括 Utilities.h
  • 现在你#define _UTILITIES_
  • 那么你确实包括MyFirstCairoPlugin.h
  • 在那里你再次包含Utilities.h
    • 但是因为#ifndef _UTILITIES_,类定义不包括在内-_UTILITIES_已经定义(见第二步)!

所以class Utilities还没有定义,你需要前向声明。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-12-10
    • 2016-08-09
    • 1970-01-01
    • 1970-01-01
    • 2022-01-07
    • 1970-01-01
    相关资源
    最近更新 更多