在面向 object 的继承中使用协方差避免冗余代码
Avoid redundancy code using covariance in object oriented inheritance
我知道以前可能有人问过这个问题,但我真的不知道要搜索什么,因为我什至不确定我选择的标题。
我想达到的目标:
如果我将 getMeasurement(int timestep) 与传感器映射 object 中不包含的整数值一起使用,则应使用特定的测量值对要求的测量值进行插值(如果可能)方法插值(...)。
它应该从地图中获得正确的两个测量值 objects 以用于超级 class 传感器中的插值并对它们进行插值,但我不知道如何以及是否可以调用插值。也许使用 Generics/Typename 或设计模式。
Sensor someSensor = ...
Measurement measurementAt2 = someSensor.getMeasurement(2);
// should interpolate value if map measurements in someSensor not has the key 2
附加信息: ASensor::measurements 仅包含 AMeasurements。
BSensor::measurements 只包含 BMeasurements。 ...这些测量包含不同的值类型,因此测量的每个子 class 需要以不同方式进行插值。
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 for inheritance 中添加一个 abstract/virtual 方法 Measurement interpolated(Measurement other, int timestep),这个签名对 subclass,因为我需要检查 class 类型并转换其他测量值。
我很欣赏用我目前正在使用的 C++11 编写代码的答案。
编辑:如果需要此信息,子classes ASensor+AMeasurement、BSensor+BMeasurement...都是独立加载的插件。
EDIT2:添加了 return 类型的方法(我忘记了)。
我不完全确定你的问题,但在 c++ 中可以获得 return 值协方差。也许这样的事情会对你有所帮助(见评论):
#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;
}
我省略了很多细节,我可能会用颜色更清楚。
如果您的问题是 interpolate()
的签名,我想您可以根据派生的 class 在模板 class 中转换 Measurement
;像
template <typename Derived>
class Measurement {
Derived interpolate (Derived other, int timestep)
{ /* do something */ }
};
class AMeasurement : Measurement<AMeasurement> {
// ...
};
class BMeasurement : Measurement<BMeasurement> {
// ...
};
p.s.: 对不起我的英语不好
如果您在 Sensor
中创建纯虚拟的 getMeasurement
函数,那么您不需要 class 基类中的 map
。然后由 Sensor
的实现来存储它们自己类型的测量值并在它们之间进行插值。您可以提供模板 class 来完成所有工作:
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> {};
我知道以前可能有人问过这个问题,但我真的不知道要搜索什么,因为我什至不确定我选择的标题。
我想达到的目标: 如果我将 getMeasurement(int timestep) 与传感器映射 object 中不包含的整数值一起使用,则应使用特定的测量值对要求的测量值进行插值(如果可能)方法插值(...)。 它应该从地图中获得正确的两个测量值 objects 以用于超级 class 传感器中的插值并对它们进行插值,但我不知道如何以及是否可以调用插值。也许使用 Generics/Typename 或设计模式。
Sensor someSensor = ...
Measurement measurementAt2 = someSensor.getMeasurement(2);
// should interpolate value if map measurements in someSensor not has the key 2
附加信息: ASensor::measurements 仅包含 AMeasurements。 BSensor::measurements 只包含 BMeasurements。 ...这些测量包含不同的值类型,因此测量的每个子 class 需要以不同方式进行插值。
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 for inheritance 中添加一个 abstract/virtual 方法 Measurement interpolated(Measurement other, int timestep),这个签名对 subclass,因为我需要检查 class 类型并转换其他测量值。
我很欣赏用我目前正在使用的 C++11 编写代码的答案。
编辑:如果需要此信息,子classes ASensor+AMeasurement、BSensor+BMeasurement...都是独立加载的插件。
EDIT2:添加了 return 类型的方法(我忘记了)。
我不完全确定你的问题,但在 c++ 中可以获得 return 值协方差。也许这样的事情会对你有所帮助(见评论):
#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;
}
我省略了很多细节,我可能会用颜色更清楚。
如果您的问题是 interpolate()
的签名,我想您可以根据派生的 class 在模板 class 中转换 Measurement
;像
template <typename Derived>
class Measurement {
Derived interpolate (Derived other, int timestep)
{ /* do something */ }
};
class AMeasurement : Measurement<AMeasurement> {
// ...
};
class BMeasurement : Measurement<BMeasurement> {
// ...
};
p.s.: 对不起我的英语不好
如果您在 Sensor
中创建纯虚拟的 getMeasurement
函数,那么您不需要 class 基类中的 map
。然后由 Sensor
的实现来存储它们自己类型的测量值并在它们之间进行插值。您可以提供模板 class 来完成所有工作:
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> {};