Instances du même objet sur scène = ctor de copie ?

Salut 4ian,

Quand un objet est placé plusieurs fois sur la scène, c’est bien le constructeur de copie qui est utilisé (ou la fonction Clone) ? :confused:
Parce que mes zones de texte possède un shared_ptr (boost) vers la sfg::Entry (la zone de texte sfgui). Et j’ai remarqué que quand deux objets identiques sont placés sur la scène, on ne voit qu’une seule des 2 zones de texte.
Que dois-je faire pour que cela se copie ? (dois-je personnaliser Clone() ou le constructeur de copie ?)
(sachant que les widgets de sfgui ne peuvent pas être copiés)

Merci d’avance.

Tu est obligé de réimplémenter la fonction Clone pour adapter le pointeur renvoyé.
Je l’ai remarqué en faisant mon extension objets son. Regarde les extensions objets texte ou objets vidéo pour prendre exemple.
Par contre, il ne faut surtout pas réimplémenter le constructeur de copie.

Chaque objet doit en effet redéfinir Clone en modifiant simplement le type de l’objet créé de cette façon :

virtual ObjSPtr Clone() { return boost::shared_ptr<Object>(new LeTypeDeMonObjet(*this));}

Cela permet à GD de copier des objets sans en connaitre le type ( Copie d’objets polymorphes : cpp.developpez.com/faq/cpp/?page … LASS_clone ).

Les objets sont créés, avec donc le constructeur, principalement lorsqu’il sont insérés dans la liste des objets initiaux, lors du chargement de la scène. Ensuite, lorsqu’ils sont créés par une action, ou placés sur la scène, les objets sont copiés avec Clone() depuis la liste des objets initiaux.

C’est tout à fait normal : Le constructeur par copie généré automatiquement par le compilateur copie chaque membre de ta classe. Pour les pointeurs ( intelligents ou non ), il ne fait également que les copier, ce qui n’implique pas la copie de l’objet pointé.

Le constructeur par copie. ( Clone() est juste un artifice permettant de copier un objet sans connaitre son type. )
Il faut le réécrire de façon à ce qu’il copie tous les membres, et fasse également une copie de l’objet pointé par le pointeur intelligent. A noter que dans ce cas, il est également bon de redéfinir également l’opérateur d’assignement ( operator= ) car cet opérateur a un rôle similaire. Pour éviter de recopier deux fois le même code, on peut procéder avec une fonction Init :

[code]
class MyObject : public Object
{
public:
//…

    /**
     * Copy constructor.
     */
    MyObject(const Object & object) : Object(object) //Ne pas oublier d'appeler le constructeur par copie de la classe de base !
    { 
        Init(object); 
    };

    /**
     * Assignement operator.
     */
    MyObject& operator=(const Object & object) {
        Object::operator=(object); //Ne pas oublier d'appeler l'opérateur = de la classe de base !
        if( (this) != &object ) 
            Init(object); 
        return *this; }

private:
    int monAttribut;
    std::string maSuperVariable;
    boost::shared_ptr<MonObjetComplique> monPointeurSurObjetComplique;

    void Init(const MyObject & other);

}

void MyObject::Init(const MyObject & other)
{
monAttribut = other.monAttribut;
maSuperVariable = other.maSuperVariable;
monPointeurSurObjetComplique = boost::shared_ptr(new MonObjetComplique(*other.monPointeurSurObjetComplique)); //On ne contente pas de copier juste le pointeur, mais bien l’objet qui est pointé.
}[/code]

Il y a deux choses à faire gaffe :
-Ne pas oublier d’appeler le constructeur par copie/l’opérateur = de la classe de base : ( En effet, par défaut le compilateur fait ça pour nous, mais dès qu’on rédéfinit ces fonctions, il faut prendre gare à le faire si notre objet hérite d’un autre ).
-Ne pas oublier de mettre à jour Init() si l’on ajoute des membres à notre classe.

C’est le coté un peu ch*ant des classes qui ont des pointeurs.

Merci de votre aide 4ian et sototo. :wink:

Moi j’ai toujours droit à des erreurs du compilateur ou de l’extension compilée quand j’implémente le constructeur de copie.

Parce que tu oublies d’appeler le constructeur de copie de l’objet parent (tout objet GD est hérité de Object) :

MyObject(const Object & object) : Object(object) //Ne pas oublier d'appeler le constructeur par copie de la classe de base !

Il n’y a pas de raison que ça marche pas, si ça t’arrive encore montre nous les bouts de code en liens avec ça.
Mais implémenter un constructeur de copie n’est utile que si l’objet a effectivement besoin de faire quelque chose en particulier durant la copie.

Je pense pas que ça empêcherait la compilation ( d’où le coté vicieux de ce genre de problème d’ailleurs ).

J’avais essayer de surcharger avant tes explications, et ça plantait à la compilation en disant un truc du genre qu’il ne pouvais pas appeler Object::Object() (j’avais pas mis le constructeur de copie)
En tout cas, ça marche maintenant. :smiley:

Oui, c’est bien ça ! Merci victor ! Je l’ai fait pour le constructeur par défaut mais pas pour le constructeur de copie… Merci encore ! :smiley: