Implementare il sovraccarico degli operatori di assegnazione in C++

Jinku Hu 12 ottobre 2023
Implementare il sovraccarico degli operatori di assegnazione in C++

Questo articolo spiegherà diversi metodi su come implementare l’overloading degli operatori di assegnazione in C++.

Utilizzare operatore di assegnazione copia per implementare l’operatore di assegnazione sovraccarico in C++

C++ fornisce la funzionalità per sovraccaricare gli operatori, un modo comune per chiamare funzioni personalizzate quando un operatore incorporato viene chiamato su classi specifiche. Queste funzioni dovrebbero avere un nome speciale che inizia con operatore seguito dal simbolo dell’operatore specifico stesso. Ad esempio, un operatore di assegnazione personalizzato può essere implementato con la funzione denominata operator=. L’operatore di assegnazione generalmente dovrebbe restituire un riferimento al suo operando di sinistra. Si noti che se l’utente non definisce esplicitamente l’operatore di assegnazione della copia, il compilatore ne genera uno automaticamente. La versione generata è abbastanza efficiente quando la classe non contiene membri di dati allocati manualmente nella memoria heap. Può anche gestire i membri dell’array assegnando ogni elemento ai membri dell’oggetto corrispondenti. Tuttavia, presenta degli svantaggi quando si tratta di membri di dati di memoria dinamica, come mostrato nel seguente codice di esempio.

#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);
}

Produzione:

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

Il codice precedente definisce esplicitamente solo il costruttore di copia, il che si traduce in un comportamento errato quando i contenuti dell’oggetto P1 sono assegnati all’oggetto P3. Notare che la seconda chiamata alla funzione P1.renamePerson non avrebbe dovuto modificare i membri dei dati dell’oggetto P3, ma l’ha fatto. La soluzione a questo è definire un operatore di assegnazione sovraccarico, ovvero un operatore di assegnazione di copia. Il frammento di codice successivo implementa la versione della classe Person che può copiare e assegnare correttamente i due oggetti della stessa classe. Si noti, tuttavia, che l’istruzione if nella funzione di assegnazione della copia garantisce che l’operatore funzioni correttamente anche quando l’oggetto è assegnato a se stesso.

#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);
}

Produzione:

Buddy Rich
Buddy Rich
Jay Roach
Buddy Rich
Jay Roach
Jay Roach
Liam White
Jay Roach
Autore: 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

Articolo correlato - C++ Class