避免在面向对象的继承中使用协方差的冗余代码



我知道这个问题以前可能被问过,但我真的不知道要搜索什么,因为我甚至不确定我选择的标题。

我想要实现的目标:如果我将getMeasurement(int timestep)与传感器对象映射中未包含的整数值一起使用,则应使用测量特定方法插值(...)对要求的测量进行插值(如果可能)。 它应该从地图中获取正确的两个测量对象,以用于超类 Sensor 中的插值并插值它们,但我不知道如何以及是否可以调用插值。也许使用泛型/类型名称或设计模式。

Sensor someSensor = ...
Measurement measurementAt2 = someSensor.getMeasurement(2); 
// should interpolate value if map measurements in someSensor not has the key 2

附加信息ASensor::测量仅包含AMeasurementsBSensor::测量只包含BMeasurements。...这些测量值包含不同的值类型,因此度量的每个子类都需要以不同的方式进行插值。

abstract class Sensor {
map<int, Measurement> measurements;
Measurement getMeasurement(int timestep);
}
class ASensor : Sensor {
...
}
class BSensor : Sensor {
...
}

abstract class Measurement {
...
}
class AMeasurement : Measurement {
AMeasurement interpolate(AMeasurement other, int timestep);
}
class BMeasurement : Measurement {
BMeasurement interpolate(BMeasurement other, int timestep);
}

如果我在 Measurement 中添加一个抽象/虚拟方法 测量插值(测量其他,int 时间步长)以进行继承,则此签名对子类不利,因为我需要检查类类型并强制转换其他 Measurement。

我很欣赏我目前正在使用的 C++11 中编码的答案。

编辑:子类ASensor+AMeasurement,BSensor+BMeasurement,...如果需要此信息,则都是独立加载的插件。

EDIT2:添加了方法的返回类型(我忘记了)。

如果你在纯虚拟中制作getMeasurement函数Sensor那么你就不需要基类中的map。然后由Sensor的实现来存储其自身类型的测量值并在它们之间进行插值。您可以提供一个模板类来完成所有工作:

class Sensor {
public:
virtual std::unique_ptr<Measurement> getMeasurement(int timestep) const = 0;
};
template<typename M>
class BasicSensor : public Sensor {
std::map<int, M> measurements;
public:
std::unique_ptr<Measurement> getMeasurement(int timestep) const override {
auto itr = measurements.lower_bound(timestep);
if (itr == measurements.end())  // Cant find measurement equal or later
return nullptr;             // than timestep so can't interpolate.
if (itr->first == timestep)                   // Found exact match so
return std::make_unique<M>(itr->second);  // don't need to interpolate.
if (itr == measurements.begin()) // Can't find measurement before
return nullptr;              // timestep so can't interpolate.
auto interpolated = std::prev(itr)->second.interpolate(itr->second, timestep);
// Copy to smart-pointer to avoid slicing
return std::make_unique<M>(interpolated); 
}
void setMeasurement(int timestep, const M& m) {
measurements[timestep] = m;
}
};
class ASensor : public BasicSensor<AMeasurement> {};
class BSensor : public BasicSensor<BMeasurement> {};

现场演示。

如果你的问题是interpolate()的签名,我想你可以根据派生类在模板类中转换Measurement;

template <typename Derived>
class Measurement {
Derived interpolate (Derived other, int timestep)
{ /* do something */ }
};
class AMeasurement : Measurement<AMeasurement> {
// ...
};
class BMeasurement : Measurement<BMeasurement> {
// ...
};

PS:对不起,我的英语不好

我不完全确定你的问题,但在 c++ 中可以获得返回值协方差。也许这样的事情会对您有所帮助(请参阅评论):

#include <iostream>
using namespace std;
struct Measurement //Abstract
{
virtual int apply(int timestep) const = 0;
virtual std::string name() const = 0;
protected:
virtual ~Measurement(){}
//...virtual Meas... etc
};
struct AMeasurement : Measurement //Implements Measurement for sensorA
{
std::string name() const override{ return "AMeasurement"; }
int apply(int timestep) const override
{
return timestep * 10;
}
};
struct BMeasurement : Measurement //Implements Measurement for sensorB
{
std::string name() const override{ return "BMeasurement"; }
int apply(int timestep) const override
{
return timestep * 20;
}
};
struct MeasurementProvider //Provides measurement
{
virtual const Measurement& getMeasurement() const = 0;
//...etc
protected:
virtual ~MeasurementProvider(){}
};
//Generalized measurement provider.
// Covariance ensure correct measurement used. Currently most basic
// implementation. Can elaborate
template <class MeasurementType>
struct GenMeasurementProvider : MeasurementProvider
{
//NOTE: MeasureType derived from Measurement, hence covariance...
const MeasurementType& getMeasurement() const override{return m_;}
MeasurementType m_;
};
// Perhaps Sensor is just a generalized Provider.
struct SensorA : GenMeasurementProvider<AMeasurement>
{
};
// Interpolate using provider instead of actual measurement to
// allow for covariance.
void interpolate(const MeasurementProvider& provider, int timestep)
{
//return type allows covariance, therefore apply to be
// called on correct type
auto const& measurement = provider.getMeasurement();
std::cout << "Result of measurement " << measurement.name() 
<< ":" << measurement.apply(timestep) << std::endl;
}
int main() {
const int timestep = 100;
interpolate(GenMeasurementProvider<AMeasurement>{}, timestep);
interpolate(GenMeasurementProvider<BMeasurement>{}, timestep);
interpolate(SensorA{}, timestep);
return 0;
}

我省略了细节,我可能会更清晰地着色。

最新更新