Voici le contexte: Un Model
a un (pointeur vers) Parameter
et un output
. Model
et Parameter
sont des classes abstraites. Nous utilisons des pointeurs de type Model*
pour manipuler diverses classes dérivées (concrètes) de Model
, dont les pointeurs vers Parameter
pointent dynamiquement vers des instances de diverses classes dérivées (concrètes) de Parameter
.Polymorphisme: cette utilisation (potentiellement intensive) de static_cast est-elle fatale?
Voici une version simplifiée des classes à titre d'exemple. Je sais new
devrait être évité ou au moins suivi par delete
, mais j'ai omis des lignes de code hors-sujet (tels que les destructeurs).
// Abstract classes
class Parameter {
public:
virtual void reinitialize() = 0;
};
class Model{
public:
Model(Parameter *argt){ ptr_param = argt; }
virtual void computeModelOutput() = 0;
double output;
Parameter *ptr_param;
};
// Concrete classes
class ACertainKindOfParameter : public Parameter{
public:
ACertainKindOfParameter(int argt){ value = argt; }
virtual void reinitialize(){ value = 1; }
int value;
};
class ACertainKindOfModel : public Model{
public:
ACertainKindOfModel(int argt) : Model(new ACertainKindOfParameter(argt)){}
virtual void computeModelOutput(){
output = 10.0 + (double)(static_cast<ACertainKindOfParameter*>(ptr_param)->value);
}
};
int main(){
ACertainKindOfModel myModel{5};
Model *ptr_model = &myModel;
ptr_model->computeModelOutput();
std::cout << ptr_model->output << std::endl; // 15
}
Ce qui me dérange dans ce code est que ACertainKindOfModel
n'a pas accès direct à value
, donc j'ai besoin apparemment d'utiliser static_cast
. Un vrai Model
aurait bien sûr un vecteur de par ex. 50 Parameter
s, pas seulement un, ce qui signifie 50 static_cast
chaque fois que le output
est calculé (ou toute autre action reposant sur des paramètres). Cela ne me semble pas être une bonne pratique, mais j'ai peut-être tort. Voyez-vous un défaut dans la conception?
Note: Je pensais que de faire Parameter
un modèle de classe, mais il ne semble pas être une option valable parce que les méthodes de Parameter
diffèrent profondément lorsque différents types de value
sont considérés. Dans l'exemple simple ci-dessus, value
est du type int
, mais dans une autre classe dérivée de Parameter
, il pourrait être du type défini par l'utilisateur, par ex. Color
avec seulement trois valeurs possibles R
, G
et B
, et reinitialize()
serait très différent de value = 1
. Un getter()
virtuel en Parameter
serait génial mais ne fonctionnerait pas non plus, à cause d'un type de retour conflictuel dans la redéfinition.
Qu'allez-vous faire avec de la valeur? Si c'est un calcul, regardez dans [Visitor Pattern] (https: //en.wikipedia.org/wiki/Visitor_pattern) donc aucune autre classe ne doit savoir quelle est la valeur. Si c'est l'affichage, pensez à ajouter un getter virtuel qui renvoie la valeur sous une forme neutre comme une chaîne. – user4581301
@ user4581301 En effet, 'value' est principalement pour le calcul comme indiqué dans le morceau de code que j'ai écrit, et il pourrait aussi apparaître dans des conditions telles que' if (value == R) ', etc. (en particulier où' value' est pas un nombre). Merci pour vos conseils sur le modèle Visitor. – Georg
* "Je sais que le neuf devrait être évité" *. Alors utilisez des pointeurs intelligents: et encore moins de ligne de code. – Jarod42