如何解决此回调包含问题?

Posted

技术标签:

【中文标题】如何解决此回调包含问题?【英文标题】:How can I fix this callback include problem? 【发布时间】:2022-01-17 20:43:53 【问题描述】:

我对 C++(和 ***)有点陌生。我正在尝试做一些事情,但我遇到了一些#include 的问题。

我想拨打我所做的回调 (from here),但我很难做到这一点。

到目前为止,这是我的代码。当我在someclass.hpp 文件中包含child.hpp 时(因为它需要Child 的有关Callback<Child> 的信息),它有一个循环包含并且编译器崩溃。

我已经阅读了关于前向声明的内容(在 someclass.hpp 文件中应该是 class Child;),在尝试之后我发现这是可行的,但我也阅读了对此的不同意见。

我的所有.hpp 文件都用#ifndef CLASSNAME #define CLASSNAME ... #endif 保护

我是否需要更改我的整个设计,或者在我的情况下最好的选择是什么?

base.hpp

#include "someclass.hpp"

class Base

    protected:
        unique_ptr<SomeClass> someClass;
;

base.cpp

#include "base.hpp"

Base::Base()

    this->someClass = make_unique<SomeClass>();


child.hpp

#include "base.hpp"

class Child : public Base

    public:
        void callbackFunction(std::string data);
        unique_ptr<Callback<Child>> callback;
;

child.cpp

#include "child.hpp"

void Child::callbackFunction(std::string data)

    /*does something*/


Child::Child()

    this->callback = make_unique<Callback<Child>>(this, &Child::callbackFunction);
    //I can call this->callback->call(data); here without problems
    
    this->someClass->setCallback(this->callback);
  //^^^^^^^^^^^^^^^ == base.someClass


someclass.hpp

#include "child.hpp" // < does crash compiler due to loop
//> someclass.hpp uses child.hpp
//> child.hpp uses base.hpp
//> base.hpp uses someclass.hpp
// and thus loop

class SomeClass

    public:
        void someFunction(std::string data);
        void setCallback(unique_ptr<Callback<Child>> callback);
        unique_ptr<Callback<Child>> callbackInstance;
;

someclass.cpp

//not 100% sure about the type of this parameter
void setCallback(unique_ptr<Callback<Child>> callback)

    this->callbackInstance = callback;


void SomeClass::someFunction(std::string data)

    //here I want to call this "Child::callbackFunction" which should go like "this->callbackInstance->call(data)" ?

也在 someclass.hpp 中

template<class T>
class Callback

    public:
        Callback(T* instance, void (T::*function)(std::string))
        
            this->callbackInstance = instance;
            this->callback = function;
        
        void call(std::string data)
        
            (callbackInstance->*callback)(data);
        
    private:
        T *callbackInstance;
        void (T::*callback)(std::string);
;

【问题讨论】:

#include_once? 我相信你是说你有一个循环包含问题。你能把template&lt;class T&gt; class Callback放在它自己的标题里吗? 是的,我可以把它放在它自己的标题中,但是包含问题仍然是一样的,因为回调需要有关子类的信息 “编译器崩溃”是什么样的?有消息吗? 编译器崩溃给出“在 child.hpp 上的 '' 标记之前的预期类名”, 我们不会称其为编译器碰撞。我们将其称为错误消息。编译器崩溃可能是编译器本身的错误。 【参考方案1】:

解决提到的错误(“在 child.hpp 上的 '' 标记之前的预期类名”),您应该删除 #include "someclass.hpp" 来自 base.hpp 并将其替换为 class SomeClass前向声明,如下所示。

base.hpp

#ifndef BASE_H
#define BASE_H
//NO NEED TO INCLUDE someclass.hpp
#include <memory>
class SomeClass;//FORWARD DECLARE SomeClass
class Base

    std::unique_ptr<SomeClass> someClass; 
    public:
    //add declaration for default constructor 
    Base();
;
#endif

base.cpp

#include "base.hpp"
#include "someclass.hpp"

//other things here

Base::Base()

    this->someClass = std::make_unique<SomeClass>();

child.hpp

#ifndef CHILD_H
#define CHILD_H
#include "base.hpp"
#include <memory>
#include "someclass.hpp"

class Child : public Base

    public:
        void callbackFunction(std::string data);
        std::unique_ptr<Callback<Child>> callback;
        //add declaration for default constrcutor 
        Child();
;
#endif

child.cpp

#include "child.hpp"

void Child::callbackFunction(std::string data)
    /*does something*/


Child::Child()

    this->callback = std::make_unique<Callback<Child>>(this, &Child::callbackFunction);
    //I can call this->callback->call(data); here without problems


someclass.hpp

#ifndef SOMECLASS_H
#define SOMECLASS_H
#include <string>
//REMOVED include child.hpp from here
class SomeClass

    public:
        void someFunction(std::string data);

        //I think I need an instance of Callback<Child> here?
;
template<class T>
class Callback

    public:
        Callback(T* instance, void (T::*function)(std::string))
        
            this->callbackInstance = instance;
            this->callback = function;
        
        void call(std::string data)
        
            (callbackInstance->*callback)(data);
        
    private:
        T *callbackInstance;
        void (T::*callback)(std::string);
;
#endif

someclass.cpp

#include "someclass.hpp"
void SomeClass::someFunction(std::string data)

    //here I want to call this "Child::callbackFunction" which should go like "this->callbackInstance->call(data)" ?


上面的程序编译执行成功,可以看到here。

总结

下面列出了我所做的一些更改:

删除了不必要的包含 在 child.hpp 和 base.hpp 中添加了默认构造函数的声明 在所有标题中添加了包含保护

【讨论】:

我的做法是不好的做法吗?又名,包括.hpp 文件中的其他.hpp 文件? 我还需要在child.cpp 中包含someClass.hpp 吗?因为如果我不这样做,我会在编译时在child.hpp 内得到一个"invalid use of incomplete type 'class SomeClass' @Bart 我还在我的回答中添加了其他文件。看看这个。在我进行更改的任何地方,我都写了 cmets。修改后程序的输出可见here。 @Bart 在.hpp 文件中包含其他.hpp 文件并不是一个坏习惯。只需包含真正需要的文件并跟踪(意味着照顾)循环依赖 好的,我看到你从 someclass.hpp 中删除了 child.hpp 包含。但是,如果我想从someclass.cpp 中的Callback&lt;Child&gt; callbackInstance 调用回调,那么最好使用前向减速或在someclass.hpp 文件中包含child.hpp

以上是关于如何解决此回调包含问题?的主要内容,如果未能解决你的问题,请参考以下文章

SWIFT - 如何解决回调发生得太晚

如何解决Objective C中成功回调的预期')'错误

函数“printf”隐式声明啥意思,该如何解决此问题?

重新排序包含目录如何解决宏重新定义问题?

MySQL:如何解决此查询的临时表错误?

如何解决此链接错误