c++inheritanceprototypal-inheritance

Can't overload the = assignment operator in derived class (as I want); call from main jumps to base class operator method


I'm trying to implement a class for a matrix with all the usual operations, just as an exercise. I implemented the common operations (+, -, ·) but my problem came when I tried to implement slicing operations—similar to Numpy. For example, if I want to make something like a[2:5,1:3] = b[10:13, 10:12] I concluded that I would need some kind of ‘smart iterator’ (I don't know the technical name) that detect how to move one row down. I have two classes:

The problem arose when I realized that the = assignment operator should be different for both classes. Because If I want to make something like a = b, then I should just destroy the allocated array in a and make a ‘re-initialization’ with the data of b (in case the dimensions changed); which, as I understood, must be ‘manually’ done. But with a[2:5,1:3] = b[10:13, 10:12], I just assign element to element without a ‘re-initialization’.

I ended up with something like

#include <stdexcept>
#include <bits/stdc++.h>
#include <iostream>

//Base class
template <class T>
class MatrixIterator
{
    public:
        MatrixIterator<T>();
        MatrixIterator<T>& operator=(const MatrixIterator<T>& b);
};

//Derived class
template <class T>
class Matrix : public MatrixIterator<T>
{
    using base = MatrixIterator<T>;
    public:
        Matrix<T>();
        Matrix<T>& operator=(const MatrixIterator<T>& b);
};

template <class T>
MatrixIterator<T>::MatrixIterator()
{
}

template <class T>
MatrixIterator<T>& MatrixIterator<T>::operator=(const MatrixIterator<T>& b)
{
    std::cout << "Base class method called" << std::endl;
    return *this;
}

template <class T>
Matrix<T>::Matrix()
{
}

template <class T>
Matrix<T>& Matrix<T>::operator=(const MatrixIterator<T>& b)
{
    std::cout << "Derived class method called" << std::endl;
    return *this;
}

int main()
{
    Matrix<int> a;
    Matrix<int> c;
    c = a;

    return 0;
}

Which outputs Base class method called.

Problem: When I do c = a, the program jumps to the base class MatrixIterator = method, while I'm expecting that it jump to the derived class Matrix method, becuse a was declared as such.

So, I changed the prototype of the function from Matrix<T>& operator=(const MatrixIterator<T>& b); to Matrix<T>& operator=(const Matrix<T>& b) and... it works fine. But I don't want that because I want to implement the = operator with the right operand understood in a broader sense; for it could be either a Matrix (a = b) or a MatrixIterator (a = b[10:13, 10:12]), both assignments requiring the left operand to be ‘re-initialized’.

I could write four methods for the four combinations of the = operator (Matrix = Matrix, Matrix = MatrixIterator, MatrixIterator = Matrix, MatrixIterator = MatrixIterator). But I'm too lazy for doing that. Actually, the whole point in creating the MatrixIterator as a base class and defining almost all the operators in that class was with the purpose of avoiding to rewrite the implementation of every operator four times.

So: If somebody understands what I'm trying to do, is there a way to make the compiler understand me? Does it worth it? Or would you say that my implementation of a base class as iterator is a poor , naïf, weak-minded strategy? Don't hesitate, say whatever you think.


Solution

  • One way is to overload assignment operator=(Matrix<T>) and then delegate the task to the operator=(MatrixIterator<T>) as shown below.

    //Derived class
    template <class T>
    class Matrix : public MatrixIterator<T>
    {
        using base = MatrixIterator<T>;
        public:
            Matrix();
            Matrix<T>& operator=(const MatrixIterator<T>& b);
            //ADDED THIS OVERLOAD
            Matrix<T>& operator=(const Matrix<T>& b)
            {
                std::cout << "Derived class Matrix parameter method called"<<std::endl;
                return (this->*static_cast<Matrix<int>& (Matrix<int>::*)(const MatrixIterator<int>&)>(&Matrix<int>::operator=))(b);//you can change this accordingly
            }
    };
    

    Live demo