Overloading the assignment operator =. Examples

Overloading the assignment operator =. Examples


Contents



1. How does an assignment statement work for class instances? What is the default assignment statement?

If the program declares a class in which the assignment operator is not overloaded, then a default assignment statement will be created for this class by the compiler. So, the default assignment statement is an assignment statement that is automatically created by the compiler to ensure that one class instance is copied to another class instance. When the default assignment operator is invoked, byte copying of one class instance to another occurs.
For example, for two instances of the classes mc1 and mc2

MyClass mc1;
MyClass mc2;

if invoke

mc1=mc2; // byte copying mc2 to mc1

then instances of classes will point to the same memory location. This is due to the fact that byte-by-byte copying of the section of memory referred to by mc2 in the section of storage referred to by mc1 will occur. As a result, all changes in mc2 will be displayed in mc1, and, conversely, all changes in mc1 will be displayed in mc2.
If you need to assign instances of classes to each other in such a way that they are not related to each other, then for this, you can implement the operator function operator=() in the class, which will perform the corresponding operations.

 

2. The general form of the overloading of the assignment operator ‘=’, which is implemented for the assignment of class objects

The assignment operator = may be overloaded for a particular class.
The general form of the assignment operator for a class named CMyClass is:

class CMyClass
{
    // fields and methods of CMyClass class
    // ...

    // overloaded assignment operator =
    // operator function operator=()
    CMyClass operator=(CMyClass mc);
};

// implementation of operator function operator=()
CMyClass CMyClass::operator=(CMyClass mc)
{
    // instructions
    // ...
}

You can implement the operator function operator=() inside the CMyClass class. In this case, the general form of the CMyClass class will be as follows:

class CMyClass
{
    // fields and methods of CMyClass class
    // ...

    // overloaded assignment operator =
    // operator function operator=()
    CMyClass operator=(CMyClass mc)
    {
        // implementation of operator function
        // ...
    }
};

 

3. The general form of the assignment operator =, which assigns a value of other types to a class object

For a class, you can overload the assignment statement in such a way that when you call the operator function operator=(), it will assign a value of another type. In this case, the general form of the class that implements the operator function operator=(), which receives an object of another type, has the form

class CMyClass
{
    // fields and methods of CMyClass class
    // ...

    // overloaded assignment operator =
    // operator function operator=()
    CMyClass operator=(type mc)
    {
        // implementation of operator function
        // ...
    }
};

here type – some data type, which can be the base type (int, float, double, …), class type, structure, enumeration.

 

4. Example of overloading an assignment operator for a class that contains single variables

The Complex class is declared, containing two internal hidden variables. These variables form the real and imaginary part of the complex number. In the Complex class, an operator function is declared.

Complex operator=(Complex cm)
{
    // ...
}

which overloads the assignment operator = for this class. When invoking an assignment operator for instances (objects) of the Complex class, this operator function will be called.
The program code of the Complex class is as follows:

// overloading of operator =
class Complex
{
private:
    double real;
    double imag;

public:
    // constructors
    Complex()
    {
        real = imag = 0.0;
    }

    Complex(double _real, double _imag)
    {
        real = _real;
        imag = _imag;
    }

    // access methods
    void GetComplex(double& _real, double& _imag)
    {
        _real = real;
        _imag = imag;
    }

    void SetComplex(double _real, double _imag)
    {
        real = _real;
        imag = _imag;
    }

    // overloaded operator '='
    Complex operator=(Complex cm)
    {
        real = cm.real;
        imag = cm.imag;
        return *this; // returns the object that generated the call
    }
};

Using the Complex class and its operator function operator=() in another method can be, for example,

// operator overload =
Complex c1(2.5, 3.8);
Complex c2;
double i,r;

i=r=0.0;
c1.GetComplex(r,i);

// a call to an operator function that overloads the operator =
c2 = c1;
c2.GetComplex(r, i); // r = 2.5; i = 3.8

// pointer to class Complex
Complex * pc3 = new Complex(1.1, 0.9);

c2 = *pc3; // overloaded assignment operator =
c2.GetComplex(r, i); // r = 1.1; i = 0.9

 

5. Example of overloading an assignment operator for a class that contains an array of numbers

In the example for the CArrayFloat100 class, the operator function operator=() is implemented, which overloads an array of float numbers. In order to simplify the code, a fixed array of numbers (100 elements) is selected in the class. The operator function performs elementwise assignment of array elements.

The program code of the CArrayFloat100 class is as follows:

class ArrayFloat100
{
private:
    float A[100]; // array of 100 numbers
    int n; // size of the array

public:
    // constructors
    ArrayFloat100()
    {
        n = 0;
        for (int i=0; i<100; i++)
            A[i] = 0.0f;
    }

    ArrayFloat100(int _n, float _A[])
    {
        for (int i=0; i<_n; i++)
            A[i] = _A[i];
        n = _n;
    }

    // access methods
    void SetAi(int index, float value)
    {
        if ((index>=0)&&(index<100)) A[index] = value;
        return;
    }

    float GetAi(int index)
    {
        if ((index>=0)&&(index<100))
            return A[index];
        return 0;
    }

    int GetN(void) { return n; }

    ArrayFloat100 operator=(ArrayFloat100 af)
    {
        n = af.n;
        for (int i=0; i<n; i++)
            A[i] = af.A[i];
        return *this;
    }
};

Demonstrate the use of an overloaded assignment operator

// operator overload = for ArrayFloat100 class
float t;
float A[] = { 5.1, 2.3, 4.1, 1.5, 2.6, 3.3 };
int n;
int d;

n = 6;
ArrayFloat100 af1(n, A);
ArrayFloat100 af2;

// checking
t = af1.GetAi(2); // t = 4.1
t = af2.GetAi(2); // t = 0
d = af1.GetN(); // d = 6
d = af2.Get(); // d = 0

// invoke of overloaded assignment operator
af2 = af1; // arrays are copied

t = af2.GetAi(2); // t = 4.1
d = af2.GetN(); // d = 6

// af1 and af2 indicate different memory locations - check
af2.SetAi(2, 0.8);
t = af2.GetAi(2); // t = 0.8
t = af1.GetAi(2); // t = 4.1

 

6. Example of overloading an assignment operator for a class that contains a dynamic array of structures of a given type

A BOOK structure is defined that describes the book. It also declares the ArrayBooks class, which implements a dynamic array of type BOOK. In the class are implemented:

  • internal variables that describe the array of books BOOK and its size;
  • constructors;
  • access methods GetBook(), SetBook();
  • operator function operator=(), which implements the assignment of instances of a class of type BOOK.

The program code of Console Application, which implements the ArrayBooks class next

#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;

struct BOOK
{
    string name; // title of the book
    string author; // book author
    int year; // book year
    float price; // book cost
};

// class that implements an array of books of type BOOK
class ArrayBooks
{
private:
    BOOK * B; // dynamic array of books
    int size; // size of the array

public:
    // class constructors
    ArrayBooks()
    {
        size = 0;
        B = NULL;
    }

    ArrayBooks(int _size, BOOK _B[])
    {
        int i;

        size = _size;

        // allocate memory for the array
        B = new BOOK[size];

        for (i=0; i<_size; i++)
            B[i] = _B[i];
    }

    ArrayBooks(int _size)
    {
        size = _size;

        B = new BOOK[size];

        for (int i=0; i<size; i++)
        {
            B[i].author = "";
            B[i].name = "";
            B[i].price = 0.0f;
            B[i].year = 0;
        }
    }

    // access methods
    BOOK GetBook(int index)
    {
        if ((index>=0) && (index<size))
            return B[index];
    }

    BOOK SetBook(int index, BOOK _B)
    {
        B[index] = _B;
    }

    // the operator function operator=()
    ArrayBooks operator=(ArrayBooks A)
    {
        int i;

        // release previously allocated memory
        if (size>0)
            delete[] B;

        size = A.size;
        B = new BOOK[size];

        for (i=0; i<size; i++)
        {
            B[i]=A.B[i];
        }
        return *this;
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    // overload the assignment operator '='
    BOOK BB[] = {
        { "title-1", "author-1", 2012, 100.0f },
        { "title-2", "author-2", 2013, 150.0f },
        { "title-3", "author-3", 2014, 200.0f }
    };

    ArrayBooks AB1(3, BB); // an instance of the ArrayBooks class
    ArrayBooks AB2(4);
    int year;
    int price;
    string author;
    string name;

    // checking AB1 values
    BOOK B;
    B = AB1.GetBook(1);
    year = B.year; // year = 2013
    author = B.author; // author = "author-2"
    price = B.price; // price = 150.0
    name = B.name; // name = "title-2"

    // checking AB2 values
    B = AB2.GetBook(2);
    year = B.year; // year = 0
    author = B.author; // author = ""
    price = B.price; // price = 0
    name = B.name;

    // INVOKE THE OVERLOADED OPERATOR FUNCTION operator=()
    AB2 = AB1;

    // checking AB2 values
    B = AB2.GetBook(2);
    year = B.year; // year = 2014
    author = B.author; // author = "author-3"
    price = B.price; // price = 200.0
    name = B.name; // name = "title-3"

    cout << "year = " << year << endl;
    cout << "name = " << name << endl;
    cout << "price = " << price << endl;
    cout << "author = " << author << endl;

    return 0;
}

 

7. Is it possible to implement an overloaded assignment statement for a class if this statement is declared as “friendly” to this class?

The assignment operator can not be declared as “friendly” to the class. If you overload the assignment statement as “class-friendly” to the class, this means that there will be an overloaded global assignment statement that is automatically called for class instances. This, in turn, can lead to confusion in the assignment statement and an increase in invisible bugs. Therefore, C ++ compilers do not allow the assignment statement to be overloaded as “friendly” to the class.

 

8. Is an overloaded assignment operator inherited by derived classes inherited?

No, it is not.

 

9. What happens if you call an assignment statement for instances of a class that does not implement the operator function operator=(), which overloads the assignment statement =?

In this case, the default assignment statement will be invoked, which is automatically generated by the compiler when declaring this class.

 

10. An example of overloading an assignment operator in a class in which an operator function receives a variable (object) of a base type (int) as a parameter

The example demonstrates overloading the assignment operator for the Value class. An overloaded assignment operator implements the assignment of an integer value to an instance of the Value class. In this case, the operator function has the form:

// operator function that receives an int parameter
Value operator=(int d)
{
    // ...
}

The declaration of the Value class and the demonstration of its use in the _tmain() function are as follows:

#include "stdafx.h"
#include <iostream>
using namespace std;

class Value
{
private:
    int d;

public:
    // constructors
    Value() { d = 0; }
    Value(int _d) { d = _d; }

    int Get(void) { return d; }
    void Set(int _d) { d = _d; }

    // operator function that receives an int parameter
    Value operator=(int d2)
    {
        d = d2;
        return *this;
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    // overloading the operator function operator=()
    // which receives the parameter of basic type
    Value v1(5); // instance of class Value
    Value v2;
    int t;

    // checking
    t = v2.Get(); // t = 0

    // INVOKE THE OPERATOR FUNCTION operator=(int)
    v2 = 8;

    // checking
    t = v2.Get(); // t = 8

    // INVOKE THE ASSIGNMENT OPERATOR THAT IS GENERATED BY DEFAULT
    v2 = v1; // byte by byte copying

    // checking
    t = v2.Get(); // t = 5

    cout << "t = " << t << endl;
    return 0;
}

In the above code, in the _tmain() function, the assignment operator for the Value class is called twice. The first time the operator function overloaded in the class which is called operator=()

v2 = 8;

The second time the statement is invoked, which for the class Value is generated by the default compiler

v2 = v1;

This statement performs the copy byte by byte operation.

 


Related topics