Implementar sobrecarga de operador de atribuição em C++

Jinku Hu 12 outubro 2023
Implementar sobrecarga de operador de atribuição em C++

Este artigo explicará vários métodos de como implementar a sobrecarga do operador de atribuição em C++.

Use operador de atribuição de cópia para implementar o operador de atribuição sobrecarregado em C++

C++ fornece o recurso para sobrecarregar os operadores, uma maneira comum de chamar funções personalizadas quando um operador integrado é chamado em classes específicas. Essas funções devem ter um nome especial começando com operador seguido pelo próprio símbolo de operador específico. Por exemplo, um operador de atribuição personalizada pode ser implementado com a função chamada operator=. O operador de atribuição geralmente deve retornar uma referência ao seu operando à esquerda. Observe que, se o usuário não definir explicitamente o operador de atribuição de cópia, o compilador gerará um automaticamente. A versão gerada é bastante capaz quando a classe não contém nenhum membro de dados alocado manualmente na memória heap. Ele pode até mesmo lidar com os membros do array atribuindo cada elemento aos membros do objeto correspondente. Embora, ele tenha deficiências ao lidar com membros de dados de memória dinâmica, conforme mostrado no código de exemplo a seguir.

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

Resultado:

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

O código acima define apenas construtor de cópia explicitamente, o que resulta em comportamento incorreto quando o conteúdo do objeto P1 é atribuído ao objeto P3. Observe que a segunda chamada à função P1.renamePerson não deveria ter modificado os membros de dados do objeto P3, mas mudou. A solução para isso é definir um operador de atribuição sobrecarregado, ou seja, operador de atribuição de cópia. O próximo trecho de código implementa a versão da classe Person que pode copiar e atribuir os dois objetos da mesma classe corretamente. Observe, porém, que a instrução if na função de atribuição de cópia garante que o operador funcione corretamente mesmo quando o objeto é atribuído a ele mesmo.

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

Resultado:

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

Artigo relacionado - C++ Class