1

I want to have an abstract class IMatrix which contains pure virtual members and one of them is an operator overloading member.

template <typename T>
class IMatrix
{
public:
    virtual T operator+(const T& b)=0;
}; 

and for the implementation I want to use a third party matrix class as for encapsulated implementation (techsoft::matrix innerMatrix).

#include "IMatrix.h"
#include "cmatrix"
template <typename T>
class ArdalanMatrix :public IMatrix<T>
{
public:
    ArdalanMatrix(int r,int c, T val=0.){
        numberOfRows = r;
        numberOfColumns = c;
        innerMatrix.resize(r, c, val);
    };
    virtual T operator+(const T& b){
        return ....??? ;
    };

private:
    techsoft::matrix<T> innerMatrix;
    int numberOfRows;
    int numberOfColumns;
};

actually I don't have any clue how to do implement operator in ArdalanMatrix class. eventually I want to use this operator overloading like this:

IMatrix<double> *M1 = new ArdalanMatrix<double>(2, 2, 2);
IMatrix<double> *M2 = new ArdalanMatrix<double>(2, 2, 2);
IMatrix<double> M3 = *M1 + *M2;
Alexander1991
  • 217
  • 5
  • 13
  • How can you add the pointer variables M1 + M2. – Sumeet Mar 07 '15 at 18:25
  • as written `+` takes a `double` and returns a `double`. I doubt that is what you want. To solve your problem, write a regularized type erasure wrapper with a pImpl pattern. See "regular type", "pImpl pattern" and "type erasure" (or "runtime concepts") for things to learn about. This is not an answer, but some breadcrumbs that might lead to one. – Yakk - Adam Nevraumont Mar 07 '15 at 18:28
  • well I suppose it's very related to the implementation of operator but maybe you're right I better write *M1+*M2 ohum? – Alexander1991 Mar 07 '15 at 18:29
  • If the intention is to add two matrix together then the operator should look like `IMatrix& operator+(const IMatrix&)`. Then, have a look at [techsoft's matrix binary operators](http://www.techsoftpl.com/matrix/doc/binaryop.htm) for your implementation. – SleuthEye Mar 07 '15 at 18:30

2 Answers2

2

The usage should look rather like: IMatrix<double> M3 = *M1 + *M2; However it would be impossible to create instantiate the IMatrix because of it is abstract class. The only thing you can do is to make the operator + return reference to matrix rather than matrix by value (by the way you have type T in the operator result which isn't probably the thing you want to gain).

W.F.
  • 13,888
  • 2
  • 34
  • 81
2

First of all, your operator+ is defined to take as parameter and return T, which is the template parameter, i.e. double in this case. It means you would be using it like this:

double M3 = M1 + 1.5;

But that's probably not what you want. You probably want the operator+ to return a matrix as well, and take another matrix as a parameter:

virtual IMatrix<T>* operator+(const IMatrix<T>& b){
    return new ArdalanMatrix( /* something */ );
};

Then you can use it like this:

IMatrix<double> *M1 = new ArdalanMatrix<double>(2, 2, 2);
IMatrix<double> *M2 = new ArdalanMatrix<double>(2, 2, 2);
IMatrix<double> *M3 = *M1 + *M2;
delete M3; // Must call `delete` because operator+ called `new`!
delete M2; // M2 and M1 must be deleted too...
delete M1;

Note: You need to declare a virtual destructor for IMatrix, otherwise you'll have a resource leak here. Here's why.

But this is bad, the delete M3 looks weird because you can't see new anywhere. A real solution would be to use smart pointers:

virtual std::unique_ptr<IMatrix<T>> operator+(const IMatrix<T>& b){
    return std::unique_ptr<IMatrix<T>>(new ArdalanMatrix( /* something */ ));
};

Then use it:

std::unique_ptr<IMatrix<double>> M1(new ArdalanMatrix<double>(2, 2, 2));
std::unique_ptr<IMatrix<double>> M2(new ArdalanMatrix<double>(2, 2, 2));
std::unique_ptr<IMatrix<double>> M3 = *M1 + *M2;
// No need to call `delete` now, unique_ptr does it automatically.

But you could also allocate the matrixes statically, which would be a whole lot simpler:

ArdalanMatrix<double> M1(2, 2, 2);    
ArdalanMatrix<double> M2(2, 2, 2);
ArdalanMatrix<double> M3 = M1 + M2;
// Destruction of M1, M2 and M3 happens automatically.

Then you can just use IMatrix pointers / references to the ArdalanMatrix objects when necessary, e.g.:

void foo(const IMatrix<double>& m) { ... }
...
foo(M1); // M1 was declared as ArdalanMatrix<double>.

Edit Apr 10 '15:

The benefit of the last approach is that the compiler takes care of deleting the objects. Moreover, static allocation should be default way to declare objects in C++, and when that's not enough, smart pointers. Raw new and delete should only be used as a last resort.

However, the solution is a bit funny because IMatrix::operator+ can't be implemented returning an IMatrix object since it's abstract. To explain it a little:

template <typename T>
class IMatrix
{
public:
    //virtual IMatrix operator+(const IMatrix& b) = 0;
    // impossible, cannot return an abstract object!

    virtual IMatrix& operator+=(const IMatrix& b) = 0;
    // possible, only returning a reference
}; 

template <typename T>
class ArdalanMatrix : public IMatrix<T>
{
public:
    ArdalanMatrix(int r, int c, T val = 0.0)
    : numberOfRows(r), numberOfColumns(c) {
        innerMatrix.resize(r, c, val);
    };
    ArdalanMatrix& operator+=(const IMatrix<T>& b) override {
        // (can override with different return type but not parameter)
        // modify innerMatrix based on b...
        return *this;
    };
    ArdalanMatrix operator+(const IMatrix<T>& b) {
        ArdalanMatrix(*this) copy; // make copy of *this
        copy += b; // modify copy based on b using operator+=
        return copy; // return it
        // or simply: return ArdalanMatrix(*this) += b;
    };

private:
    techsoft::matrix<T> innerMatrix;
    int numberOfRows;
    int numberOfColumns;
};

Now you can do this:

int main() {
    ArdalanMatrix<double> M1(2, 2, 2);
    ArdalanMatrix<double> M2(2, 2, 2);
    IMatrix<double>& R1 = M1;
    IMatrix<double>& R2 = M2;

    R1 += R2; // add R2 to R1, works. M1 will get modified

    //const IMatrix<double>& R3 = R1 + R2;
    // doesn't work, can't add two IMatrices

    // However, since we know that R1 and R2 are really ArdalanMatrices,
    // we can do this and it works as expected:
    const IMatrix<double>& R3 = dynamic_cast<ArdalanMatrix<double>&>(R1)
                              + dynamic_cast<ArdalanMatrix<double>&>(R2);
    // R3 is now really a ArdalanMatrix too
}
Community
  • 1
  • 1
Emil Laine
  • 41,598
  • 9
  • 101
  • 157
  • would you please explain the last approach for me a little more please? what's the benefit in this? actually what I want to do is to implement a matrix interface which deals with another another Matrix class through it's core so that I can handle it later more easily. is the last approach offers me the same benefit? – Alexander1991 Apr 09 '15 at 20:27
  • Thank you so much, it's very beautiful and I learned many from it, but it's a bit hard to use. because I'll have to define over thousand or more matrix for what I'm doing. I explain what I want to do in the last comment, would you please recommend me other method except using interface to deal with my problem? Thanks in advanced. – Alexander1991 Apr 10 '15 at 05:39
  • 1
    I figured my last comment would be a new question so I posted it here: [http://stackoverflow.com/questions/29554383/an-efficient-matrix-interface-in-c] – Alexander1991 Apr 10 '15 at 06:04