Quel est le meilleur modèle d'utilisation de membre de données polymorphes en C++? Le plus simple que je connaisse est d'utiliser un simple pointeur.C++ Modèle de meilleure pratique d'utilisation de membre de données polymorphes
Par exemple, si le type de membre de données ne sont pas polymorphes:
class Fruit {
public:
int GetWeight() { return 1; }
};
class Food {
public:
Food(Fruit f=Fruit()) : m_fruit(f) {}
void SetFruit(Fruit f) { m_fruit = f; }
Fruit GetFruit() { return m_fruit; }
int Test() { return m_fruit.GetWeight(); }
private:
Fruit m_fruit;
};
// Use the Food and Fruit classes
Food food1; //global scope
void SomeFunction() {
Fruit f;
food1.SetFruit(f);
}
int main() {
Fruit fruit1, fruit2;
Food food2(fruit1);
food2.SetFruit(fruit2);
food2.SetFruit(Fruit());
SomeFunction();
food1.Test();
food2.Test();
return 0;
}
Il est facile d'utiliser les classes de plusieurs façons avec possibilité minimum d'erreurs.
Maintenant, si nous faisons Fruit classe de base (utilisez polymorphes), c'est le plus simple/meilleur que je peux penser à:
class Fruit {
public:
virtual int GetWeight() { return 0; }
};
class Apple : public Fruit {
public:
virtual int GetWeight() { return 2; }
};
class Banana : public Fruit {
public:
virtual int GetWeight() { return 3; }
};
class Food {
public:
Food(Fruit& f=defaultFruit) : m_fruit(&f) {}
void SetFruit(Fruit& f) { m_fruit = &f; }
Fruit& GetFruit() { return *m_fruit; }
int Test() { return m_fruit->GetWeight(); }
private:
Fruit* m_fruit;
static const Fruit m_defaultFruit = Fruit();
};
// Use the Food and Fruit classes
Food food1; //global scope
void SomeFunction() {
Apple a;
food1.SetFruit(a);
}
int main() {
Apple a;
Banana b;
Food food2(a);
food2.SetFruit(b);
food2.SetFruit(Apple()); //Invalid ?!
SomeFunction(); //Weakness: the food1.m_fruit points to invalid object now.
food1.Test(); //Can the compiler detect this error? Or, can we do something to assert m_fruit in Food::Test()?
food2.Test();
return 0;
}
Y at-il une meilleure façon de le faire? J'essaie de rester simple en n'utilisant aucune nouvelle instruction/suppression. (Note: doit être en mesure d'avoir une valeur par défaut)
MISE À JOUR: Lets Prenons un exemple plus pratique:
class Personality {
public:
void Action();
};
class Extrovert : public Personality {
..implementation..
};
class Introvert : public Personality {
..implementation..
};
class Person {
...
void DoSomeAction() { personality->Action(); }
...
Personality* m_personality;
};
L'objectif est d'avoir des personnes avec des personnalités différentes, et pour le rendre facile à ajouter plus de personnalité par sous-classe. Quelle est la meilleure façon de mettre en œuvre cela? Puisque, logiquement, nous n'avons besoin que d'un objet pour chaque type de Personnalité, cela n'a pas beaucoup de sens pour une Personne de copier ou d'assumer la propriété d'un objet Personnalité. Pourrait-il y avoir une différence d'approche/conception qui ne nous oblige pas à faire face à un problème de copie/propriété?
+1 Belle description claire. Vous pouvez utiliser la clémence du type de retour co-variant pour que les pointeurs de retour de la fonction clone de l'objet dérivé reviennent aux types dérivés ... préserve juste un peu plus de connaissances du compilateur, documente mieux ce qui se passe et évite parfois la distribution. –
La faiblesse de passer la propriété de la «Fruit» passée est que nous ne pouvons pas assigner le même objet plusieurs fois. Par exemple, nous avons 'Apple * a = new Apple (certains paramètres),' et nous voulons faire 'Food f1 (a);', 'Food f2 (a);', et ainsi de suite. Alors, cela signifie-t-il que la stratégie "make a copy" est meilleure? – leiiv
@Tony: Pourriez-vous me donner un exemple? Peut-être posté comme une nouvelle réponse? – leiiv