Bonjour,
J'aimerais savoir si quand on a l'implémentation d'un constructeur :, est-ce qu'on est obligé de renseigner le paramètre lors de l'appel du constructeur ? Car celui-ci ne pointe vers rien...Code:Constr::Constr(QObject *parent=0){}
Version imprimable
Bonjour,
J'aimerais savoir si quand on a l'implémentation d'un constructeur :, est-ce qu'on est obligé de renseigner le paramètre lors de l'appel du constructeur ? Car celui-ci ne pointe vers rien...Code:Constr::Constr(QObject *parent=0){}
Non : le =0 dit que si le paramètre n'est pas précisé, 0 est sa valeur par défaut.
ah ok.
Quel intérêt, dans la pratique, lors de l'initialisation d'un objet, de lui passer en paramètre un pointeur vers un objet parent ?
On m'a déjà dit que cela pouvait servir à détruire l'objet automatiquement si le parent était détruit.
Tout cela est pour moi un peu abstrait : dans le cas où l'on créer une GUI, l'objet est automatiquement détruit à la fin du programme... ?
Salut,
Il existe un design pattern nommé "composite" qui permet, pour faire simple, de gérer une relation "contenant" à "contenu" sous une forme arborescente, et de gérer n'importe quel élément que l'on retrouve dans cette arborescente sans (trop) devoir se poser la question de savoir exactement à quel type d'objet on a affaire.
Ce patron de conception est régulièrement utilisé dans le domaine de l'IHM car on peut estimer que, qu'il s'agisse de la fenêtre principale, d'un menu, ou de n'importe quel élément visuel utilisable, nous avons "simplement" affaire à... un élément visuel, susceptible d'en contenir d'autres... ou non.
Seulement, alors que le "sens classique" dans lequel les informations sont généralement transmises dans une relation de contenant à contenu va du contenant vers le contenu, il n'est pas rare, surtout dans le domaine de l'IHM (mais pas uniquement) que le sens du passage de l'information doive être inversé et que le contenu doive être en mesure d'envoyer des informations à son contenant.
Seulement, pour y arriver, il faut bien... disposer d'une référence (au sens générique, et non au sens C++ du terme ;)) vers le contenant, pour autant qu'il y en ait un.
Et comme il est malgré tout impensable de transmettre cette information de manière systématique à toutes les fonctions membres, la meilleure solution consiste à déclarer un membre du type du contenant dans le contenu.
Mais comme il est impossible de faire rentrer quelque chose qui prend plus d'espace mémoire que l'objet dans lequel on essaye de le faire entrer, et qu'il faut aussi être en mesure de déterminer s'il y a effectivement un contenant, le membre dans le contenu qui lui permettra de s'adresser au contenant ne peut être... qu'un pointeur.
Comme, enfin, on conseille fortement de faire en sorte que tout objet soit "complet" et utilisable dés le moment de sa création (il n'est vraiment pas recommandé de devoir invoquer trente six mutateurs avant de pouvoir utiliser l'objet :P) il est largement préférable d'initialiser le parent dés le constructeur ;)
Bonjour,
Pourquoi ne pas le faire avec une référence ?
Le pointeur ne prend pas de la mémoire lui ?
Merci d'avance à bientôt.
Parce qu'un objet peut ne pas avoir de parent (c'est le cas par exemple des fenêtres principales, qui ne sont pas contenues dans une autre)Citation:
Pourquoi ne pas le faire avec une référence ?
Or un pointeur peut être nul mais pas une référence
Ok j'ai compris l'idée globale c'est vachement bien pensé en fait. De plus je ne savais pas qu'un objet d'une classe de base prenait plus d'espace mémoire qu'un objet d'une classe dérivée.
Tu as très mal compris ce que j'essayais d'expliquer...
Une classe de base prend, fatalement, moins d'espace mémoire que n'importe quelle classe qui en dérive, mais....
Si tu as une classe Element qui agit comme le "contenu" et une classe Collection qui agit comme "contenant" d'un nombre fixe et clairement déterminé d'élément de type de Element, le code serait proche de
Element prenant moins d'espace en mémoire que Collection, il devient tout à fait impossible de placer sous forme de valeur un objet de type Collection dans element, simplement parce que l'on se retrouve face à un serpent qui se bouffe la queue: la taille de Collection dépend de la taille de Element, qui augmente elle-même de la taille de Collection, qui augmentera parce que la taille de Element vient de le faire (et ainsi de suite).Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 class Base { //... }; class Element : public Base { // ... }; ///sizeof(Element) >= sizeof(Base) class Collection /* : public Base */ { //... private: Element[N]; //N est une constante connue à la compilation }; //sizeof(Collection) >= sizeof(Collection) * N >= sizeof(Base) * N
Si tu veux mettre une référence (au sens général du terme) vers le contenant dans le contenu, tu dois donc veiller à ce que ce que tu essaye de placer dans le contenu nécessite un espace mémoire fixe et clairement défini.
Les deux seules choses qui utilisent un espace mémoire fixe et clairement défini quel que soit le type d'objet référencé sont les pointeurs et les références (qui sont souvent implémentées, au niveau du code binaire exécutable, exactement de la même manière que les pointeurs ;)).
Les différences principales entre les deux, c'est qu'un pointeur peut obtenir une valeur connue comme représentant l'absence d'objet référencé (NULL / nullptr dans la nouvelle norme), et que nous pouvons changer l'objet référencé (sous réserve qu'il soit de type compatible), alors que l'objet référencé par la référence a une garantie de non nullité, et qu'il nous est impossible de faire en sorte de changer l'objet référencé.
Merci pour la réponse.
Je reviens avec une autre question : dans l'implémentation d'un constructeur j'ai ceci :Mon souci est au niveau de la compréhension du 2ème paramètre, soit :Code:Constr::Constr(bibi &a, bubu &b=bubu()){}
Je ne comprend pas cette ligne : que signifie-t-elle ?Code:bubu &b=bubu()
(je me dis que si l'on ne renseigne pas ce paramètre, le paramètre par défaut sera la référence sur b... mais comme on ne renseigne pas le paramètre alors une référence sur rien ça colle pas...)
Merci d'avance. Bonne journée.
Cordialement, Gizmo.
Bonjour,
Ici, comme tu l'as compris, bubu() est la valeur par défaut de la variable b (b étant de type bubu&). En fait, bubu() appelle le constructeur par défaut de la class bubu. Ce qui signifie donc, concrètement, que si tu ne fournis pas de 2nd paramètre lorsque tu vas appeler ce constructeur, b sera automatiquement crée en utilisant le constructeur par défaut de la classe bubu.Code:Constr::Constr(bibi &a, bubu &b=bubu()){}
ah bon d'accord... donc c'était bien ça... cool alors.
merci pour la réponse. bonne journée à vous
Si ce n'est que cela devrait etre
Pour a, cela n'a pas énormément d'importance, hormis que cela placera une restriction qu'il s'agit impérativement d'éviter pour b:Code:Constr::Constr(bibi & a, bubu const & b=bubu()){}
il faut absolument fournir un objet existant en argument pour a car il n'y a pas moyen de créer une variable temporaire anonyme pour une référence non constante.
tu ne pourrais donc, par exemple, pas écrire un code proche de
La raison est simple: la norme estime que, comme tu ne pourra de toutes manières pas réutiliser la variable anonyme temporaire en dehors de la fonction lors de l'appel de laquelle elle est créée, il ne sert strictement à rien d'en permettre la modification ;)Code:
1
2
3
4
5
6 int main { Constr c(bibi(/* parametres */, bubu(/* autres paramètres*/) ); /* la suite */ return 0; }