Implement Assignment Operator Overloading in C++

This article will explain several methods of how to implement assignment operator overloading in C++.

Use copy-assignment operator to Implement Overloaded Assignment Operator in C++

C++ provides the feature to overload operators, a common way to call custom functions when a built-in operator is called on specific classes. These functions should have a special name starting with operator followed by the specific operator symbol itself. E.g., a custom assignment operator can be implemented with the function named operator=. Assignment operator generally should return a reference to its left-hand operand. Note that if the user does not explicitly define the copy assignment operator, the compiler generates one automatically. The generated version is quite capable when the class does not contain any data members manually allocated on the heap memory. It can even handle the array members by assigning each element to the corresponding object members. Although, it has shortcomings when dealing with dynamic memory data members, as shown in the following example code.

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

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

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

Output:

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

The above code defines only copy-constructor explicitly, which results in incorrect behavior when P1 object contents are assigned to the P3 object. Note that the second call to the P1.renamePerson function should not have modified the P3 object’s data members, but it did. The solution to this is to define an overloaded assignment operator i.e., copy-assignment operator. The next code snippet implements the version of the Person class that can copy assign the two objects of the same class correctly. Notice, though, the if statement in the copy-assignment function guarantees that the operator works correctly even when the object is assigned to itself.

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

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

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

Output:

Buddy Rich
Buddy Rich
Jay Roach
Buddy Rich
Jay Roach
Jay Roach
Liam White
Jay Roach
Contribute
DelftStack is a collective effort contributed by software geeks like you. If you like the article and would like to contribute to DelftStack by writing paid articles, you can check the write for us page.

Related Article - C++ Class

  • Deep Copy VS Shallow Copy in C++