Constructeurs de copie et opérateurs d’affectation de copie (C++)

Remarque

À compter de C++11, deux types d’affectation sont pris en charge dans la langue : l’affectation de copie et l’affectation de déplacement. Dans cet article « assignation » signifie assignation de copie, sauf spécification contraire. Pour plus d’informations sur l’affectation de déplacement, consultez Constructeurs de déplacement et Opérateurs d’affectation de déplacement (C++).

Les opérations d'assignation et d'initialisation génèrent une copie des objets.

  • Affectation : lorsque la valeur d’un objet est affectée à un autre objet, le premier objet est copié dans le deuxième objet. Par conséquent, ce code copie la valeur de b :a

    Point a, b;
    ...
    a = b;
    
  • Initialisation : l’initialisation se produit lorsque vous déclarez un nouvel objet, lorsque vous passez des arguments de fonction par valeur ou lorsque vous retournez par valeur à partir d’une fonction.

Vous pouvez définir la sémantique de « copie » pour les objets de type classe. Considérez par exemple le code suivant :

TextFile a, b;
a.Open( "FILE1.DAT" );
b.Open( "FILE2.DAT" );
b = a;

Le code précédent peut signifier « copier le contenu de FILE1. DAT à FILE2. DAT » ou « ignorer FILE2 ». DAT et apportez b un deuxième handle à FILE1.DAT. » Vous devez attacher la sémantique de copie appropriée à chaque classe, comme suit :

  • Utilisez un opérateur operator= d’affectation qui retourne une référence au type de classe et accepte un paramètre passé par const référence, par exemple ClassName& operator=(const ClassName& x);.

  • Utilisez le constructeur de copie.

Si vous ne déclarez pas de constructeur de copie, le compilateur génère un constructeur de copie membre pour vous. De même, si vous ne déclarez pas d’opérateur d’affectation de copie, le compilateur génère un opérateur d’affectation de copie membre pour vous. La déclaration d’un constructeur de copie ne supprime pas l’opérateur d’affectation de copie généré par le compilateur, et vice versa. Si vous implémentez l’une ou l’autre, nous vous recommandons également d’implémenter l’autre. Lorsque vous implémentez les deux, la signification du code est claire.

Le constructeur de copie prend un argument de type ClassName&, où ClassName est le nom de la classe. Par exemple :

// spec1_copying_class_objects.cpp
class Window
{
public:
    Window( const Window& );            // Declare copy constructor.
    Window& operator=(const Window& x); // Declare copy assignment.
    // ...
};

int main()
{
}

Remarque

Définissez le type de l’argument const ClassName& du constructeur de copie dans la mesure du possible. Cela empêche le constructeur de copie de modifier accidentellement l’objet copié. Il vous permet également de copier à partir d’objets const .

Constructeurs de copie générés par le compilateur

Les constructeurs de copie générés par le compilateur, comme les constructeurs de copie définis par l’utilisateur, ont un seul argument de type « référence à class-name ». Une exception est lorsque toutes les classes de base et les classes membres ont des constructeurs de copie déclarés comme prenant un seul argument de type constclass-name>. Dans ce cas, l’argument du constructeur de copie généré par le compilateur est également const.

Lorsque le type d’argument du constructeur de copie n’est pas const, l’initialisation en copiant un const objet génère une erreur. L’inverse n’est pas vrai : si l’argument est const, vous pouvez initialiser en copiant un objet qui n’est pas const.

Les opérateurs d’affectation générés par le compilateur suivent le même modèle pour const. Ils prennent un seul argument de type ClassName& , sauf si les opérateurs d’affectation dans toutes les classes de base et membres prennent des arguments de type const ClassName&. Dans ce cas, l’opérateur d’affectation généré pour la classe prend un const argument.

Remarque

Lorsque les classes de base virtuelle sont initialisées par des constructeurs de copie, qu’elles soient générées par le compilateur ou définies par l’utilisateur, elles ne sont initialisées qu’une seule fois : au moment où elles sont construites.

Les implications sont similaires au constructeur de copie. Lorsque le type d’argument n’est pas const, l’affectation à partir d’un const objet génère une erreur. L’inverse n’est pas vrai : si une const valeur est affectée à une valeur qui n’est pas const, l’affectation réussit.

Pour plus d’informations sur les opérateurs d’affectation surchargés, consultez Affectation.