CONNEXION
  • RetourJeux
    • Sorties
    • Hit Parade
    • Les + populaires
    • Les + attendus
    • Soluces
    • Tous les Jeux
    • Gaming
  • RetourActu Gaming
    • News
    • Astuces
    • Tests
    • Previews
    • Toute l'actu gaming
  • RetourBons plans
    • Bons plans
    • Bons plans Smartphone
    • Bons plans Hardware
    • Bons plans Image et Son
    • Bons plans Amazon
    • Bons plans Cdiscount
    • Bons plans Decathlon
    • Bons plans Fnac
    • Tous les Bons plans
  • RetourJVTech
    • Actus High-Tech
    • Intelligence Artificielle
    • Smartphones
    • Mobilité urbaine
    • Hardware
    • Image et son
    • Tutoriels
    • Tests produits High-Tech
    • Guides d'achat High-Tech
    • JVTech
  • RetourCulture
    • Actus Culture
    • Culture
  • RetourVidéos
    • A la une
    • Gaming Live
    • Vidéos Tests
    • Vidéos Previews
    • Gameplay
    • Trailers
    • Chroniques
    • Replay Web TV
    • Toutes les vidéos
  • RetourForums
    • Hardware PC
    • PS5
    • Switch 2
    • Xbox Series
    • Switch
    • Pokemon pocket
    • FC 25 Ultimate Team
    • League of Legends
    • Tous les Forums
  • PC
  • PS5
  • Xbox Series
  • Switch 2
  • PS4
  • One
  • Switch
  • iOS
  • Android
  • MMO
  • RPG
  • FPS
En ce moment Genshin Impact Valhalla Breath of the wild Animal Crossing GTA 5 Red dead 2
Liste des sujets

[c++] objets imbriqués (stupid question)

saleGauss
saleGauss
Niveau 9
23 février 2008 à 23:03:08

Bonjour !

Voila j'ai une question un peu idiote mais comme ca fais un bail que j'ai pas imbriqué des objets dans des autres (j'utilise plus souvent des pointeurs dans des objets), je me posait cette petite question :

class A
{
B b; // contient une instance de la classe B
A()
~A()
};

class B
{
// données
B()
~B()
};

Bien, ma question est la suivante :
est-ce que par defaut le constructeur de A va invoquer le constructeur de B pour créer "b" ?
En fait le fait d'écrire ma question vient presque de me donner la réponse : oui.

Enfin je suppose.
En meme temps, je ne me vois pas trop invoquer le constructeur de B moi meme pour créer "b".

C'est vrai que je suis plus habitué à avoir un B* b
et donc à faire un b = new B dans mon constructeur de A (oui... faut suivre :d) et là c'est tout de suite plus explicite que le constructeur de A va invoquer le constructeur de B pour créer "b"

Mais je pense que là ca a le meme effet, si ce n'est que b est créé de manière statique.

Voila, si vous pouvez affirmer/infirmer mes dires, c'est gentil !
Merci bcp, et bonne soirée !

DrTenma
DrTenma
Niveau 6
24 février 2008 à 10:45:34

Oui, par defaut le constructeur de A va invoquer le constructeur PAR DEFAUT de B ?
Si B n'a pas de constructeur par defaut, il faut utiliser un pointeur au lieu d'une instance.

godrik
godrik
Niveau 30
24 février 2008 à 11:28:10

tu peux egalement ne pas utiliser le constructeur par defaut de B si tu le souhaites, sans allouer l'objet dynamiquement. Il faut alors utiliser les liste d'initialisation. Un exemple:

class B
{
// données
B();
B(int);
~B();
};

class A
{
B b; // contient une instance de la classe B
A()//ceci appele le constructeur par defaut de B
{}
~A()
};

class A
{
B b; // contient une instance de la classe B
A()
:b(12)//ceci appele le constructeur B::int pour b
{}
~A()
};

Attention avec les listes d'initialisation!!!
les objets sont construit dans l'ordre de DECLARATION et pas dans l'ordre de la liste.

ainsi la construction suivante pose probleme:

class C
{
B b1;
int a;
C()
:a(12), b1(a)
{}
};

pose probleme de facon sur, en effet, b1 est déclaré avant a, il sera construit avant lui bien que a apparaisse avant b1 dans la liste d'initialisation.

saleGauss
saleGauss
Niveau 9
24 février 2008 à 12:42:37

Merci beaucoup pour vos réponse, elle sont très claires.
Comme je suis dans le cas de classes qui n'ont qu'un seul constructeur par defaut, je n'ai pas de probleme pour choisir le constructeur que je veux utiliser, et donc pas à me soucier des listes d'initialisation.

En tout cas je saurais que c'est faisable aussi.

Tiens, tant que j'y suis je vais vous poser deux autres chtites questions indépendantes :

/* question 1 */
conceptuellement, il vaut mieux mettre des pointeurs dans des objets pour les imbriquer, ou mettre directement une instance dans un objet ?

En clair, faut-il privilégier une deux deux constructions :

class A
{
B b;
A();
~A();
};

ou plutot :

class A
{
B* b;
A(){b = new B};
~A();
};

J'imagine que ca dépend des objets manipulés et de la signification qu'on veut leur donner.
Mois je suis dans le cas d'une grosse classe EngineSysteme qui va manager pas mal de grosses classe : AffichageSysteme, InputSysteme, ...

Je ne sais pas trop laquelle des deux constructions utiliser, sachant qu'en fait ma classe EngineSysteme ne fera presque rien toute seule, elle se contentera de faire le "jonction" entre des gros modules.
Je ne sais donc pas trop si il vaudrait mieux faire :

class EngineSysteme
{
AffichageSysteme affichage;
InputSysteme input;
...
};

ou class EngineSysteme
{
AffichageSysteme* affichage;
InputSysteme* input;
};

qu'est-ce que qui conceptuellement est le mieux ?
Il faut savoir que je n'aurais qu'une seule instance de Engine Systeme, et donc une seule instance de AffichageSysteme et InputSysteme, donc ces classes représentent des objets qui seront unique.

Raaaah, il faudrait vraimment que je me décide à lire un bouquin sur la conception orienté objet pour m'aider à mieux penser ce genre de choses là.

/* question 2 */

C'est encore un probleme de conception.
Quand je veux passer à une fonction un objet, j'ai plusieurs possibilités :

fontion(OBJET objet); // VERSION 1
Bon, là il va recevoir l'objet par recopie, donc pas de modif possible sur l'objet original.

fonction(OBJET& objet) // VERSION 2
La il le recoit par référence (que je vois comme un pointeur déguisé), et les eventuelles modifs que je vais faire sur objet affecterons sa version d'origine.

fonction(OBJET* objet) // VERSION 3
La je recois un pointeur, donc c'est leger.
mais avec mon pointeur je vais pouvoir modifier objet.
Ou juste utiliser objet.

fonction(const OBJET& objet) // VERSION 4
La je vais recevoir l'objet par référence, mais je serais certain qu'il ne sera pas modifié par ma fonction.

Idéallement, quand-est-ce que je devrais utiliser chacune des version ci dessus ?
Bon, deja ca dépend de si je veux pouroir faire des modifs sur mon paramètre.
Y'a-t'il d'autres paramètres à prendre en compte pour décider ?

En terme de rapidité, quels sont les perfs relatives ? Bon la version 1 est la plus lente, ca c'est sur puisque il faut recopier toute mon instance.
Mais entre les autres, ca donne quoi ?

Conclusion entre mes deux questions :
vous l'aurez compris, j'ai du mal à utiliser à bon escient un objet, un pointeur sur l'objet, des passages par reference, par reference constante, et par pointeur.

Si vous pouvez me donner quelques conseils...

ps : Désolé pour mon post over long.
Et désolé pour avoir poster ca dans ce forum, "programmation" aurait été plus adapté mais je me suis gouré hier soir, et c'est l'habitude da passer ici. Mes excuses à Lapintade.

godrik
godrik
Niveau 30
24 février 2008 à 13:16:08

Je ne suis pas une reference en architecture logicielle, il faut donc prendre ma réponse a la question 1 avec des pincettes:
J'utilise generalement les objets composites quand les deux objets sont intimement lié.
Par exemple, Table n'a pas de sens sans Pied.

J'utilise une version pointeur quand l'objet pointé a du sens par lui meme. C'est a dire qu'il peut etre partagé par plusieurs objets en meme temps.

Pour la deuxieme question:
La version 1 (par recopie) est tres rarement utile. L'interet est bien de faire une copie de l'objet et c'est rarement ce que l'on veut faire.
Cependant, il peut y avoir des exceptions.

La version 2 et 3 sont equivalement en terme de performance, Les references devraient etre traité comme des pointeurs apres compilation. Cependant, il y a une différence sématique : un pointeur peut etre NULL, une reference pointe toujours sur un objet!

La version 4 est celle qu'il faut préféré si on compte pas modifier l'objet. Cependant, attention. Ce n'est pas parcequ'un objet est const qu'il ne peut pas etre modifié. Il y a le mot clé "mutable" en C++ qui permet de changer certaines variables alors que l'objet est const. Ceci est principalement utiliser pour implanter des caches logiciels ou outils de trace. C'est assez peu problematique du moment qu'on le sait.

Finalement, je dirai qu'il y a un cas ou on peut vouloir utiliser la version 1 plutot que 4 qui est le cas des access concurrents. Si on a deux threads qui accedent au meme objet, il peut etre interressant de copier l'objet et de laisser les deux traitements se faire en parallele. A partir du moment ou il y en a un qui est accedé seulement en lecture.
Cela s'approche des "dirty read" en base de données.

KeepSmile
KeepSmile
Niveau 4
24 février 2008 à 13:36:08

Pour la question 1:

Personnelement je favorise les pointeurs quand je peux, car premièrement ca évite de faire des includes dans les fichiers headers ce qui évite trop de dépendance entre les fichiers, imagine tu modifies le fichier A.h qui est inclus dans B.h, C.h, D.h ...etc tous ces fichiers vont être rebuild (du moins les fichiers .cpp hein), deplus j'évite de mettre les attributs dans le fichier .h en faisant de l'insulation quand c'est possible. Mais tout ceci dépend de ce que tu recherche, de l'ampleur du projet ...etc

Pour la question 2:

Tout dépend de ce que tu cherche à faire, comme tu dis la solution 1 est souvent évité et on préférera passer par une const référence apres le choix entre la solution 2 et 3 est légère, souvent on se pose la question suivante:

Si je modifie cet objet, est ce qu'il peut y avoir une erreur ? si oui on passe par un pointeur et si jamais une erreur on le met à NULL sinon on passe par un référence (pour la lisibilité et pour éviter de faire des conneries dessus, genre des delete ou autre)

Après pour des bouquins d'architecture, Large Scale C++ Software Design by John Lakos est vraiment énorme :) (merci LGV).

Mais bien sur mes réponses du dessus dépend de beaucoup de chose et notamment du contexte et des contraintes.

saleGauss
saleGauss
Niveau 9
24 février 2008 à 15:16:44

merci beaucoup pour vos éléments de reponse.
Concernant la question1, j'envisageais exactement la chose comme Godrik, à savoir si l'objet qui va etre imbriqué possede ou non un sens à lui tout seul. Si c'est le cas j'en fais un pointeur dans ma classe, sinon un objet composite.
Je pense que c'est une manière acceptable de voir la chose.

Bon, en meme temps c'est vrai que c'est du chipotage sur l'architecture logicielle.
Mais comme mon projet est asser gros j'avais besoin de clarifier les choses avec moi même.

Pour la question2 c'est à peu près ce que j'imaginais en terme de perf puisque instinctivement je concevais une reference comme un pointeur déguisé.
Donc je trouve logique que les performances soient semblables.

Pour la lecture que tu me conseille keepsmile, j'irais voir à la BU de ma fac si il y est.
Je vais peut etre aussi relire le bouquin de Stroustrup (la version anglaise si je la trouve, de meilleure qualité je trouve), pas mal de choses m'avaient interessées mais par manque de temps je n'avais pas pu aborder tout ce qui m'interessait.

Ca me fait bizare de m'etre posé ce genre de question là, parce que je code depuis pas mal de temps en c++, mais il y a des petites choses qui sont difficiles à assimiler parfaitement, et à structurer dans son esprit.
C'est peut etre aussi parce que le C++ ne possede pas de "fondements essentiels" mais tout un tas de choses rajoutés sur le C, par fois un peu de maniére presque incohérente.
Il y a tout un tas de subtilité et de petites différence qui rendent sa parfaite maitrise très difficile je trouve.

Par exemple, quand j'ai appris caml et haskell après avoir appris le c++, j'ai été surpris par le si faible nombre de choses essentielles à savoir.
Ces langages sont vraimment constituée d'une toute petite "boule" principale avec laquelle on peut faire plein plein de choses.

Voila, c'était ma pensée de l'aprem, et sur ces considérations philosophiques des langages, je vais me laver les cheveux :-) :-)

Bonne aprem à tous, profitez bien du petit bout du week-end qui reste.

Franck

godrik
godrik
Niveau 30
24 février 2008 à 18:20:11

ce qui se passe avec le C++, c'est que c'est un langage multi paradigme. Il y a tellement de subtilité dans le langage qu'il n'y a pas une facon de bien ecrire les choses. Mais plusieurs facon distincte.

Sous forums
  • Aide à l'achat Mac
  • Création de sites web
  • Internet
  • Macintosh
  • Création de Jeux
  • Linux
  • Programmation
  • Steam Deck
  • Hardware
La vidéo du moment