gpt4 book ai didi

c++ - 在 C++ 中创建具有相同接口(interface)的类返回的 bool 值的反转的推荐方法?

转载 作者:行者123 更新时间:2023-11-30 03:35:45 26 4
gpt4 key购买 nike

我有一个用例涉及返回 bool 值(指示传感器的状态)的传感器对象集合。在某些情况下,集合对象对传感器值的倒数感兴趣,但我想对这两种情况使用相同的接口(interface),以便集合不需要跟踪它。一个例子可能是

结果 = 传感器 A |不是(传感器B)

其中使用相同接口(interface)访问 sensorA 和 not(sensorB) 的值。我为此提出了几个解决方案,但没有一个看起来像我最初预期的问题那么简单。

首先,我可以通过创建另一个继承相同基接口(interface)并执行转换的类来实现目标。然而,这似乎有点笨拙,因为我必须为每个传感器实例化一个反转对象:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

class ObservedSensorBase
{
public:
virtual bool getState(void) = 0;

protected:
ObservedSensorBase() { inverted = new InvertSensor(this); }
};

class ConcreteSensor : public ObservedSensorBase
{
public:
ConcreteSensor(bool state) :mState(state) {}

bool getState(void) { return mState; }
private:
bool mState;
};

class InvertSensor : public ObservedSensorBase
{
public:
InvertSensor(ObservedSensorBase *sensor) :mSensor(sensor) {}

bool getState(void) { return !mSensor->getState(); }
private:
ObservedSensorBase *mSensor;
};


int main()
{
ConcreteSensor sensorA(true);
InvertSensor notSensorA(&sensorA);

vector <class ObservedSensorBas*> sensors;

sensors.push_back(&sensorA);
sensors.push_back(&notSensorA);

for (class ObservedSensorBase* it : sensors)
{
cout << it->getState() << endl;
}


return 0;
}

打印:

1
0

理想情况下,我正在寻找能够返回反转功能的原始具体传感器类。如果我向每个具体传感器添加一个公共(public)类,我可以这样做:

class ConcreteSensor : public ObservedSensorBase
{
public:
ConcreteSensor(bool state) :mState(state),inv(this) {}

bool getState(void) { return mState; }

class InvertSensor inv;
private:
bool mState;
};

...

sensors.push_back(&sensorA.inv);

打印

0

但这似乎有点麻烦,因为它是每个具体类中的一个新变量。我不能将它添加到基类中,因为 InvertSensor 是从基类继承的,所以 InvertSensor 没有完全定义并且不能被实例化(至少我没能这样做)。

我研究过的另一种方法是使用对象工厂:

ObservedSensorBase *invertFactory(ObservedSensorBase *sensor)
{
static map<ObservedSensorBase *, ObservedSensorBase *> m;

// Create an instance of the inverter for this object if it doesn't already exist
if (m.find(sensor) == m.end())
{
m[sensor] = new InvertSensor(sensor);
}

// Provide the inverting object for the passed sensor
return m[sensor];
}

...

sensors.push_back(invertFactory(&sensorA));

打印

0

我还缺少其他解决方案吗?理想情况下,每个具体实例都可以从类中继承一些固有的东西,但在这一点上它也变成了一个智力挑战 :)

--- 编辑 ---感谢到目前为止的评论。

为了更好地阐明目标,这是一个用 Arduino 控制模型铁路信号的小项目。出于此处的目的,假设信号只能显示绿色和红色。当信号“保护”的任何轨道占用电路或开关方向表明火车不安全时,它们会显示红色(否则显示绿色)。

轨道检测和开关方向对象都是基础传感器的具体实例,但创建此用例的是开关方向。如果我们有两个信号,每个信号都在“保护”通向单个开关的双轨端的两种方法,一个信号将“按原样”使用开关方向传感器,而另一个将想要使用倒置的传感器值(表示开关的方向)。

我希望能够在将 加载到包含它们的信号对象时反转传感器的状态表示,以避免必须在信号对象中存储单独的“反转此信号”指示,或手动实例化一个单独的执行反转的对象。

有点像

Signal1 保护 SensorA (trackA) 和 Switch B

Signal2 保护 SensorC (trackC) 而不是 (SwitchB)

这是一个信号示例(一个传感器容器,将它们全部组合在一起)例如

class Signal
{
public:
void protect(class ObservedSensorBase *sensor) { mSensors.push_back(sensor); }

void periodicLoop(void)
{
bool anyProtectedSensorActive = false;

for ( auto it = mSensors.begin();
it != mSensors.end() && !anyProtectedSensorActive;
++it)
{ anyProtectedSensorActive |= (*it)->getState(); }

if(anyProtectedSensorActive)
{ /* set Signal Red */ }
else
{ /* set signal Green */ }
}

private:
vector <class ObservedSensorBase*> mSensors; // protected sensors
};

...


Signal signal1;
Signal signal2;

signal1.protect(&sensorA);
signal1.protect(&sensorB);

signal1.protect(&sensorC);
signal1.protect(&notSensorB);

但是,在按照@Jason C 的建议将一些东西放在基类中(在提出问题之前或在他的建议之后我无法开始工作)之后,我突然想到我可以创建

// Invert Sensor and ObservedSensorBase are declared as above...

class InvertedSensorBase : public ObservedSensorBase
{
public:
InvertedSensorBase() : inverted(this) {}
class InvertSensor inverted;
};

// Change the inheritance of the concrete observer
//class ConcreteSensor : public ObservedSensorBase
class ConcreteSensor : public InvertedSensorBase

现在 SensorA.inverted 似乎非常符合要求。

当然,由于这主要是一个回到 C++ 并在长期缺席后学习 C++11 的副项目,如果有人对任何一点有替代建议,我会非常高兴看到他们。

最佳答案

如果您想要一个真正不费力的解决方案,您可以存储 pair<ObservedSensorBase*,bool>在您的容器中, bool 值是您是否要反转,并且只需让您的逻辑反转基于该值的值 bool :

typedef pair<ObservedSensorBase *,bool> SensorWithFlag; // ...or something

vector<SensorWithFlag> sensors;
sensors.push_back(SensorWithFlag(sensor1, true)); // invert
sensors.push_back(SensorWithFlag(sensor2, false)); // don't invert

// then later when you use it, say 'n' is an index:
bool state = (sensors[n].first->getState() != sensors[n].second);

但如果不是,我想你可以在基数中进行反演:

class ObservedSensorBase {
...
public:
void setInvertState (bool invertState) {
invertState_ = invertState;
}
bool getState () {
return invertState_ != getState_(); // != is xor
}
protected:
virtual bool getState_ () = 0;
private:
bool invertState_;
};

然后所有子类实现getState_而不是 getState , 并且都可以通过设置 setInvertState(true) 来反转结果。 .

但这看起来很奇怪。也许您可以添加更多关于您的容器如何使用这些值的详细信息。我觉得总体上可能有更好的方法来构建您的程序和算法。


另一种选择是使用“反相滤波器”选项,但在基础中对其进行管理:

class ObservedSensorBase {
...
public:
ObservedSensorBase (...) : inv_(this) { ... }
InvertSensor * inverted () { return &inv_; }
private:
InvertSensor inv_;
};

然后你可以添加mySensor->inverted()需要时添加到您的容器中。这有以下注意事项:

  • 不要调用 ObservedSensorBase 的任何虚拟方法来自 InvertSensor的构造函数。
  • 不要调用 InvertSensor 的任何方法这可能导致调用虚拟基方法,来自 ObservedSensorBase的构造函数。
  • inverted() 返回的指针删除传感器时无效。

前两点很重要,因为this构造子类时还不会完全构造。

这样一来,每个传感器都会自动拥有自身的倒置版本,您无需手动管理它们。


另一种解决方案是围绕传感器对象创建包装器,但要保持它们简单并将它们直接存储在容器中而不是存储指向它们的指针,以简化内存管理。例如:

class SensorValue {
public:
SensorValue (ObservedSensorBase *s, bool invert)
: s_(s), i_(invert) { }
bool getState () { return i_ != s_->getState(); }
ObservedSensorBase * sensor () { return s_; }
private:
ObservedSensorBase *s_;
bool i_;
};

// then later, let's say you have some sensors:
ObservedSensorBase *sensor1 = ...;
ObservedSensorBase *sensor2 = ...;

// you can have containers like this:
vector<SensorValue> collection1, collection2;

// and you can use normal/inverted states as needed:
collection1.push_back(SensorValue(sensor1, false)); // normal values
collection1.push_back(SensorValue(sensor2, false));
collection2.push_back(SensorValue(sensor1, true)); // and inverted
collection2.push_back(SensorValue(sensor2, true)); // at the same time

// if you ever need the sensor object itself you can use SensorValue#sensor:
for (vector<SensorValue>::iterator i = collection1.begin();
i != collection1.end(); ++ i)
{
bool state = i->getState(); // normal or inverted, transparent to us here
ObservedSensorBase *sensor = i->sensor(); // can be used for whatever.
// note that i->getState() != i->sensor()->getState() if we're
// using an inverted SensorValue.
}

// and they aren't pointers, you can just do this with no leaks:
collection1.clear();
collection2.clear();

// although of course you still do this for sensor cleanup:
delete sensor2;
delete sensor1;

这在概念上有点类似于倒置传感器对象方法,除了SensorValue。不是 ObservedSensorBase ,它是轻量级的且可廉价复制,您可以将它们直接存储在容器中而不是传递指针。

这与存储非常相似,例如pair<ObservedSensorBase*,bool> (你存储传感器和反转标志的地方)在你的容器中,除了不像 pair它给你一个方便的getState()成员,具有一定的语义。

关于c++ - 在 C++ 中创建具有相同接口(interface)的类返回的 bool 值的反转的推荐方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41031316/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com