如何解决此回调包含问题?
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<class T> 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<Child> callbackInstance
调用回调,那么最好使用前向减速或在someclass.hpp
文件中包含child.hpp
?以上是关于如何解决此回调包含问题?的主要内容,如果未能解决你的问题,请参考以下文章