Instanciation d'un attribut de classe dans son constructeur puis accès avec un get
Bonjour,
J'ai un problème lié à la conception d'un code en C++.
J'utilise 2 classes, A et B. La classe A a pour attribut un pointeur vers B et inversement.
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class A {
public:
A();
~A();
void setB(string s);
void setB(string s1, string s2);
B* getB() const;
private:
B* b_;
};
class B {
public:
B(A* a);
A* getA() const;
private:
A* a_;
}; |
Pour rajouter un peu de complexité, B est une classe abstraite avec deux sous-classes B1 et B2. B1 ajoute un attribut string et B2 en ajoute deux.
La classe A n'est pas obligée d'avoir un B (dans ce cas, le pointeur est nullptr), par contre, un B possède toujours un A.
C'est pourquoi en pratique, c'est A qui instancie B dans la méthode setB :
- En fonction du nombre de paramètres, on instancie un B1 ou un B2
- Si b_ n'est pas nullptr, on fait le delete qui faut avant d'instancier un nouveau B1 ou B2 (je précise que pour un A donné, on peut remplacer un B1 par un B2 et inversement)
Ces classes sont utilisées dans le programme et j'ai notamment trois vector de A, B1 et B2, vA, vB1 et vB2.
Pour finir et donner un peu de contexte, mon programme est une IHM pour une base de données.
Dans la BD, j'ai trois table, LesA[nomA], LesB1[nomA, s] et LesB2[nomA, s1, s2] :
- Je lis d'abord la table LesA et je crée mes objets A que j'ajoute à vA
- Je lis ensuite les table LesB1 et LesB2, j'utilise setB pour créer les objets B et je les récupère avec le getter pour les mettre dans vB1 ou vB2.
Mon problème c'est que si je dois rappeler setB sur un objet A, en interne je vais bien supprimer le B précédent mais il sera toujours dans vB1 ou vB2.
Pareil, si je delete un A, il va delete B dans son destructeur mais les objets seront toujours dans les vector.
J'ai l'impression que cette situation est causée par une mauvais conception des classes mais j'arrive pas à voir comment m'y prendre différemment.
Votre avis et votre aide sont les bienvenus, merci.
Utiliser le destructeur de B, des listes chainées, et éventuellement des pointeurs intelligents
Bonjour,
Est-ce que tu as la possibilité d'utiliser des listes chaînées à la place des vectors (as-tu vraiment besoin de l'indiçage fournit par les vectors) ?
Si cela te convient, tu pourrais considérer chaque instance de B comme une cellule de ta liste chaînée (avec un "précédent" et "suivant").
Alors, tu pourrais mettre dans le destructeur de B le retrait de cette liste chainée, avec un simple :
Code:
1 2 3 4
| ~B() {
next_->previous_ = previous_;
previous_->next_ = next_;
} |
De plus, en bonus, as-tu déjà utilisé les pointeurs intelligents std::unique_ptr ou std::shared_ptr ? Parce qu'ils seraient pratiques pour rendre encore plus naturel la manipuation des instances de B. En effet, affecter b_ détruirait automatiquement l'élément précédent s'il y en avait un, et détruire A détruirait automatiquement l'éventuel B associé.