我有两个类:DESEngine和UserEvents。 DESEngine应该是UserEvents的“所有者”,但是UserEvents应该可以通过以下方式访问DESEngines变量和方法:Owner->Method();

但是根据图片,我遇到了多个错误:Error List(错误已包含在帖子结尾的文本表单中)

我几乎可以肯定,几乎所有错误都是由于循环依赖引起的,但我一直无法解决它们:/

DESEngine.h

#ifndef DESENGING
#define DESENGINE

#pragma once
#include <string>
#include <vector>
#include <unordered_map>
#include "boost/any.hpp"
#include "GlobalVariables.h"
#include "TextParser.h"
#include "UserEvents.h"

class GlobalVariables;
class TextParser;
class UserEvents;

class DESEngine
{
public:
// System Classes
    GlobalVariables GVar_User = GlobalVariables();
    GlobalVariables GVar_EventLabels = GlobalVariables();
    UserEvents UsrEvt = UserEvents(*this);

    DESEngine();
    ~DESEngine();

    // Irrelevant stuff omitted

private:
   // Irrelevant stuff omitted
    std::unordered_map<std::string, void(DESEngine::*)(const std::string&)> SystemFunctionPointerMap;
    void DESEngine::ExtractEventParameter(std::string &WordBlock, std::vector<boost::any> &EvtParams);
};

#endif


UserEvents.h

#ifndef USEREVENTS
#define USEREVENTS


#pragma once
#include <string>
#include <vector>
#include <unordered_map>
#include <typeinfo>
#include <boost/any.hpp>
// #include "DESEngine.h" --> moved to DESEngine.cpp

class DESEngine;

class UserEvents
{

public:

    // Class constructor / destructor
    UserEvents(DESEngine &Engine);
    ~UserEvents();

    // Select which function(parameters) to call
    int UserEvents::Choose(const DESEngine::EventWithParams &Event);


private:
    DESEngine Owner;

    // Here we have an unordered map that assigns User Function (pointer) to each Key (string / Alias / Event Name)
    std::unordered_map<std::string, void(UserEvents::*)(const std::vector<boost::any>&)> UserFunctionPointerAliasMap;
// Irrelevant stuff omitted
    };

    #endif

C2079 'UserEvents::Owner' uses undefined class 'DESEngine'  33
C2027 use of undefined type 'DESEngine' 29
C4430 missing type specifier - int assumed. Note: C++ does not support default-int  29
C2143 syntax error: missing ',' before '&'  29
C2079 'UserEvents::Owner' uses undefined class 'DESEngine'  33
C2440 '=': cannot convert from 'DESEngine' to 'int' 11
C2511 'int UserEvents::Choose(const DESEngine::EventWithParams &)': overloaded member function not found in 'UserEvents'    24
C2671 'UserEvents::Choose': static member functions do not have 'this' pointers 27
C2228 left of '.at' must have class/struct/union    27
C2027 use of undefined type 'DESEngine' 29
C4430 missing type specifier - int assumed. Note: C++ does not support default-int  29
C2143 syntax error: missing ',' before '&'  29
C2079 'UserEvents::Owner' uses undefined class 'DESEngine'  33
C2027 use of undefined type 'DESEngine' 29
C4430 missing type specifier - int assumed. Note: C++ does not support default-int  29
C2143 syntax error: missing ',' before '&'  29

最佳答案

由于这是has aDESEngine之间的UserEvents关系,并具有其类结构,因此您可以稍微重新设计不会丢失任何功能的类。设计上的这种细微变化应改善内存管理以及类之间的关系或联系。当一个类Has a <T>Owns到另一个objectclassstructure时,所属类仅需要在其自己的header中包含对象header,而不需要class prototype declaration 。现在,属于另一个类的类不应在其自己的标头中包含所属类的header,但确实需要class prototype declaration and needs to include the owning class's header in its implementation`文件。

另外,关于所有权关系,这正是智能指针发挥作用的地方。由于您的DESEngine类对象拥有一个UserEvents对象,因此在拥有的类中具有std::unique_ptr<T>是安全的。这将为您创建一个T指针,并且还应有助于管理内存的分配和取消分配以及重置指针,以避免内存泄漏和悬而未决的指针问题。这样,只有DESEngine的该实例才能访问和修改该实例或UserEvents的副本。现在,如果您需要其他资源来修改并可以访问引擎以外的UserEvents,则可以轻松地将其更改为std::shared_ptr<T>

这是一组类的示例...



所有者

#ifndef OWNER_H
#define OWNER_H

#include "SomeObject.h" // This class is owned by Owner since Owner has a SomeObject class object

/*No Need To Have Class Prototype Declaration*/ // #include "SomeClass.h"
// This does however need to be included in "Owner.cpp"

class Owner {
    std::unique_ptr<SomeObject> myRestrictedObject;
    std::shared_ptr<SomeObject> mySharedResourceObject;
};
#endif // OWNER_H


Owner.cpp

#include "stdafx.h" // if used
#include "SomeObject.h"
#include "SomeOtherClasses.h"

// Class Body Or Implementation Definitions


SomeObject.h

#ifndef SOME_OBJECT_H
#define SOME_OBJECT_H

// Since Owner.h already has #include `THIS.h` we do not want to include it here but we will need this:
class Owner;

class SomeObject {
private:
     // Google Search For Using Friend relationship.
};

#endif // SOME_OBJECT_H


SomeObject.cpp

// We need to include Owner.h here
#include "Owner.h"


现在,当使用另一个拥有的SomeObject时,您只需通过使这两个类彼此成为完整朋友类或通过特定方法彼此成为朋友,就可以减轻包含指向拥有对象的指针或引用的需要。在每个班级。这样,您就可以控制两个类如何与其他类交互的内部关系。通过精心设计,如果产品代码的用户具有良好的结构并且这些功能可以实现它们的意图并相应地命名,那么您的产品代码用户就不必担心函数,类及其方法以及模板的内部实现细节。便于阅读。

现在,如果您希望该对象包含其拥有的对象的指针,那么您可能希望不使用朋友,而是还要避免让他们中的任何一个接受指针或彼此的对象。换句话说,两个类都应具有默认构造函数,如果一个依赖另一个构造函数,则它总是可以首先使用默认构造函数,然后可以使用initialize或update方法通过该方法将类的内部变量指针更改为另一个类。在某些情况下或需要时,您可以让一个类是静态类,而不是实际对象。然后,您将需要一个静态的get函数,以将其*this作为静态指针返回给您,然后其他依赖类也可以使用该静态指针,尤其是如果您只有该类对象的1个实例时。

对于使用可以很容易被谷歌查看的朋友。至于后面的选项,如果需要,我可以举一个小例子。

既然您的应用程序似乎应该只具有DESEngineUserEvents的单个实例,否则就不需要具有多个这些实例,除非如果您要合并一堆UserEvents对象,则可以派生这两个类来自基本的Singleton接口。然后确保这两个对象都声明了一个指向自身的静态指针以及该指针的get方法。然后,使用该对象的其他类可以使用该静态指针,或类似地使用,但不是静态单例,可以使用智能指针,甚至可以使用两者的组合。这完全取决于您的特定需求。

涉及循环依赖时,includes和类原型声明的位置是最重要的决定因素。现在,您还显示了这两个类与其他头文件一起使用的其他类,并且其中一个可能也是罪魁祸首,但直到现在才出现在这两个类中。

我还想补充一下WhozCraig的评论,即您正在将DESEngine的引用传递给UserEvents构造函数。因此,让我们看看编译器试图从您那里了解什么...

在源代码中某些其他函数中,您正在创建DESEngine的实例,例如;

main.cpp

#include "DESEngine.h"

int main() {
    DESEngine engine; // This is okay because you declared it with a default constructor.

}


因此,编译器进入DESEngine.h并在定义之前查看此类的声明,并说自己好吧,我需要一个UserEvents类,让我们进入其构造函数,好的,此构造需要Reference到对象,并且这是从DESEngine变量声明到当前的DESEngine的,而我尚未完成声明或定义UserEvents对象的过程。因此,它会绕圈尝试根据声明完成定义。

关于c++ - 我该如何解决这种循环依赖关系?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43729000/

10-09 05:48