2016-06-23 2 views
1

Je sais que ce problème a pu être posé auparavant, mais je ne sais vraiment pas quoi chercher, car je ne suis même pas sûr du titre choisi.Éviter le code de redondance utilisant la covariance dans l'héritage orienté objet

Ce que je veux atteindre: Si je getMeasurement (int timestep) avec une valeur entière non contenue dans la carte d'un objet capteur, la mesure demandé doit être interpolé (si possible) en utilisant une mesure méthode spécifique interpoler (...). Il devrait obtenir les deux objets Measurements corrects de la carte à utiliser pour l'interpolation dans le super classe Sensor et les interpoler, mais je ne sais pas comment et si je peux appeler l'interpolation. Peut-être avec des génériques/typename ou des modèles de conception.

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

Informations additionnelles:asensor :: mesures ne contient que AMeasurements. BSensor :: mesures contient juste BMeasurements. ... Ces mesures contiennent différents types de valeurs et, par conséquent, chaque sous-classe de mesure doit être interpolée différemment.

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); 
} 

Si j'ajoute une méthode abstraite/virtuelle mesure interpolée (mesure autre, int timestep) dans la mesure de l'héritage, cette signature ne serait pas bon pour la sous-classe, comme je l'ai besoin de vérifier le type de classe et jette aussi l'autre mesure.

J'apprécie une réponse possible de coder en C++ 11, que j'utilise actuellement.

EDIT: Les sous-classes ASensor + AMeasurement, BSensor + BMeasurement, ... sont des plugins chargés indépendamment si ces informations sont nécessaires.

EDIT2: Ajout des types de retour des méthodes (que j'ai oublié).

+0

Comment remplissez-vous les 'mesures'? – erip

+0

Écrivez un petit morceau de code de conducteur montrant comment vous avez l'intention d'appeler le code. Peut-être que nous pouvons alors commenter. –

+0

Le capteur a une méthode pour lire les données spécifiques d'une chaîne en utilisant une méthode abstraite/virtuelle dans Mesures pour créer des mesures en utilisant seulement des parties spécifiques de la chaîne. Cette méthode est implémentée différemment dans chaque sous-classe. –

Répondre

0

Si vous faites la fonction getMeasurement dans Sensor pur, alors vous n'avez pas besoin virtuel du map dans la classe de base. Ensuite, il appartient aux implémentations de de stocker des mesures de leur propre type et de les interpoler entre elles.Vous pouvez fournir une classe de modèle pour faire tout le travail:

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> {}; 

Live demo.

+0

Merci beaucoup, j'ai même essayé de mettre la carte dans la sous-classe mais cela a produit de la redondance de code pour moi, mais je n'ai pas eu cette idée de mettre un template template entre. –

0

Je ne suis pas entièrement sûr de votre question, mais en C++ on peut obtenir une covariance de retour. Peut-être quelque chose comme ça pourrait vous aider (voir les commentaires):

#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; 
} 

J'ai omis de allot détails que je vais peut-être colorie avec plus de clarté.

0

Si votre problème est la signature de interpolate(), je suppose que vous pourriez transformer Measurement dans une classe de modèle dépendant de la classe dérivée; quelque chose comme

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

class AMeasurement : Measurement<AMeasurement> { 
    // ... 
}; 

class BMeasurement : Measurement<BMeasurement> { 
    // ... 
}; 

p.s .: désolé pour mon mauvais anglais

+0

N'est pas maintenant le problème, que je ne peux pas mettre ces différentes mesures dans une carte ensemble. Quelle serait ma super classe? –

+0

@AndreMeixner Pourquoi avez-vous besoin de mettre toutes ces différentes mesures dans une carte ensemble? Chaque capteur n'a que des mesures de son propre type? –

+0

Si je devais mettre une carte de mesures spécifiques dans le capteur approprié, cela causerait d'autres problèmes. Exemple: Pour implémenter un capteur dans le capteur, j'ai besoin de lancer chaque sous-classe de mesure avant de revenir. –