我目前正在通过automatak使用opendnp3软件包。 https://github.com/automatak/dnp3/blob/2.0.x/cpp/examples/outstation/main.cpp。
我无法理解的是如何在Struct(超出类范围的定义)中更新信息,而不将结构传递给类(我认为我不能作为我的代码来做)从未真正调用过该方法,因此我无法更改调用该方法时传递给该方法的内容。
继承图:
我已经通过创建自己的类(MyCommandHandler)覆盖了SimpleCommandHandler类中的虚拟方法DoOperate。 DoOperate函数提供的所有功能均由asio提供。
struct State
{
double value0 = 0;
double value1 = 0;
bool binary0 = false;
bool binary1 = false;
};
State state;
class MyCommandHandler : public SimpleCommandHandler
{
public:
static std::shared_ptr<ICommandHandler> Create()
{
return std::make_shared<MyCommandHandler>();
}
MyCommandHandler() : SimpleCommandHandler(CommandStatus::SUCCESS) {}
protected:
void DoOperate(const ControlRelayOutputBlock& command, uint16_t index, OperateType opType) {
////*** This is where I need to update the Struct ***////
//// state.value0 = 30; ////
//// state.value1 = 30; ////
//// state.binary0 = true; ////
//// state.binary1 = true; ////
}
}
};
我能想到的唯一方法是使Struct全局化,但是根据我在这里Making Global Struct in C++ Program所读的内容,这似乎是不好的编码实践。
简而言之,我想知道-使用由某个外部事件触发的方法(DoOperate)修改类外部数据(Struct)的最佳实践是什么?
我已经为此苦苦挣扎了一段时间了,因此我们将不胜感激。
谢谢!
答案 0 :(得分:0)
全局对象的问题之一是您可能会遇到初始化或销毁顺序的问题。因此,从理论上讲,DoOperate
可能会在State state
尚未初始化或已经被销毁时(在on应用程序退出时可能会被隐藏)时调用。
但是即使您的应用程序可能不是这种情况,您仍然希望通过设计使其安全。
对于您的MyCommandHandler
,调用DoOperate
并不重要,因此MyCommandHandler
对象要么需要在整个生存期内拥有state
,要么您可以如果仅在调用DoOperate
时才需要将它作为参数传递给DoOperate
。
如果将其作为参数传递给DoOperate
,则调用该运算符的对象应在整个生命周期内拥有状态对象,或者应将其作为调用DoOperate
的函数的参数。 ...
如果您真的想使用全局状态对象,则可以这样:
std::shared_ptr<State> get_global_state() {
static std::shared_ptr<State> state = std::make_shared<State>();
return state;
}
class MyCommandHandler : public SimpleCommandHandler
{
public:
MyCommandHandler() : state_(get_global_state()) {}
static std::shared_ptr<ICommandHandler> Create()
{
return std::make_shared<MyCommandHandler>();
}
MyCommandHandler() : SimpleCommandHandler(CommandStatus::SUCCESS) {}
void DoOperate(const ControlRelayOutputBlock& command, uint16_t index, OperateType opType) {
// state_-> value0 = ...
}
protected:
std::shared_ptr<State> state_;
};
或者类似的代码,如果将其作为参数传递给DoOperate
struct HandlerCaller {
void call_handlers() {
for( auto &handler : handlers ) {
handler->DoOperate(state_.get(), /*...*/ )
}
}
std::shared_ptr<State> state_;
}
class MyCommandHandler : public SimpleCommandHandler
{
void DoOperate(State * const state, const ControlRelayOutputBlock& command, uint16_t index, OperateType opType) {
// state-> value0 = ...
}
};
我个人不喜欢单例,但是重要的是这里的所有权。