Implémenter la surcharge des opérateurs d'affectation en C++

Jinku Hu 12 octobre 2023
Implémenter la surcharge des opérateurs d'affectation en C++

Cet article explique plusieurs méthodes d’implémentation de la surcharge des opérateurs d’affectation en C++.

Utilisez opérateur d'affectation de copie pour implémenter l’opérateur d’affectation surchargé en C++

C++ fournit la fonctionnalité de surcharge des opérateurs, un moyen courant d’appeler des fonctions personnalisées lorsqu’un opérateur intégré est appelé sur des classes spécifiques. Ces fonctions doivent avoir un nom spécial commençant par operator suivi du symbole d’opérateur spécifique lui-même. Par exemple, un opérateur d’affectation personnalisé peut être implémenté avec la fonction nommée operator=. L’opérateur d’affectation doit généralement renvoyer une référence à son opérande de gauche. Notez que si l’utilisateur ne définit pas explicitement l’opérateur d’affectation de copie, le compilateur en génère un automatiquement. La version générée est tout à fait capable lorsque la classe ne contient aucun membre de données alloué manuellement sur la mémoire du tas. Il peut même gérer les membres du tableau en affectant chaque élément aux membres d’objet correspondants. Cependant, il présente des inconvénients lors du traitement des membres de données de mémoire dynamique, comme indiqué dans l’exemple de code suivant.

#include <iostream>
#include <string>
#include <utility>
#include <vector>

using std::cout;
using std::endl;
using std::string;
using std::vector;

class Person {
 public:
  Person() {
    name = new string;
    surname = new string;
  };
  Person(string n, string s) {
    name = new string(std::move(n));
    surname = new string(std::move(s));
  }
  Person(Person &p) {
    name = new string(*p.name);
    surname = new string(*p.surname);
  }

  ~Person() {
    delete name;
    delete surname;
  }

  void renamePerson(const string &n, const string &s) {
    name->assign(n);
    surname->assign(s);
  };

  void printPerson() { cout << *name << " " << *surname; }

 private:
  string *name;
  string *surname;
};

int main() {
  Person P1("Buddy", "Rich");
  Person P2 = P1;

  P1.printPerson();
  cout << endl;
  P2.printPerson();
  cout << endl;

  P1.renamePerson("Jay", "Roach");

  P1.printPerson();
  cout << endl;
  P2.printPerson();
  cout << endl;

  Person P3;
  P3 = P1;
  P1.printPerson();
  cout << endl;
  P3.printPerson();
  cout << endl;

  P1.renamePerson("Liam", "White");

  P1.printPerson();
  cout << endl;
  P3.printPerson();
  cout << endl;

  exit(EXIT_SUCCESS);
}

Production:

Buddy Rich
Buddy Rich
Jay Roach
Buddy Rich
Jay Roach
Jay Roach
Liam White
Liam White

Le code ci-dessus définit explicitement uniquement constructeur de copie, ce qui entraîne un comportement incorrect lorsque le contenu de l’objet P1 est affecté à l’objet P3. Notez que le deuxième appel à la fonction P1.renamePerson n’aurait pas dû modifier les données membres de l’objet P3, mais il l’a fait. La solution à cela est de définir un opérateur d’affectation surchargé, c’est-à-dire un opérateur d’affectation de copie. L’extrait de code suivant implémente la version de la classe Person qui permet de copier correctement les deux objets de la même classe. Remarquez, cependant, l’instruction if dans la fonction d’affectation de copie garantit que l’opérateur fonctionne correctement même lorsque l’objet est affecté à lui-même.

#include <iostream>
#include <string>
#include <utility>
#include <vector>

using std::cout;
using std::endl;
using std::string;
using std::vector;

class Person {
 public:
  Person() {
    name = new string;
    surname = new string;
  };
  Person(string n, string s) {
    name = new string(std::move(n));
    surname = new string(std::move(s));
  }
  Person(Person &p) {
    name = new string(*p.name);
    surname = new string(*p.surname);
  }

  ~Person() {
    delete name;
    delete surname;
  }

  Person &operator=(const Person &p) {
    if (this != &p) {
      *name = *(p.name);
      *surname = *(p.surname);
    }
    return *this;
  }

  void renamePerson(const string &n, const string &s) {
    name->assign(n);
    surname->assign(s);
  };

  void printPerson() { cout << *name << " " << *surname; }

 private:
  string *name;
  string *surname;
};

int main() {
  Person P1("Buddy", "Rich");
  Person P2 = P1;

  P1.printPerson();
  cout << endl;
  P2.printPerson();
  cout << endl;

  P1.renamePerson("Jay", "Roach");

  P1.printPerson();
  cout << endl;
  P2.printPerson();
  cout << endl;

  Person P3;
  P3 = P1;
  P1.printPerson();
  cout << endl;
  P3.printPerson();
  cout << endl;

  P1.renamePerson("Liam", "White");

  P1.printPerson();
  cout << endl;
  P3.printPerson();
  cout << endl;

  exit(EXIT_SUCCESS);
}

Production:

Buddy Rich
Buddy Rich
Jay Roach
Buddy Rich
Jay Roach
Jay Roach
Liam White
Jay Roach
Auteur: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook

Article connexe - C++ Class