Thread: Overloading operator+

  1. #1
    Registered User
    Join Date
    Oct 2009
    Posts
    117

    Overloading operator+

    I am trying to make a Matrix class that has overloaded operators for +, =, and *. I am stuck on overloading + and =.
    Code:
    //assignment operator
    Matrix &Matrix::operator=(Matrix &whatever) {
    	if(getRows() != whatever.getRows() || getCols() != whatever.getCols()) {
    		cout<<"The matrices are not the same size!"<<endl;	//if they are the same size
    		return 0;
    	}
    	else {	//else if they are not the same size
    		for(int r=0;r<getRows();r++) 
    			for(int c=0;c<getCols();c++) 
    				this->getTerms()[r][c] = whatever.getTerms()[r][c];	//set the term
    	}	//end else
    	return *this;
    }	//END OPERATOR=
    The problem here is that the compiler won't let me return 0. If the matrices are not the same size, I want the function (or whole program) to end there. How can I end the function?

    Code:
    Matrix Matrix::operator+(Matrix &additive) {	
    	if( (getRows() != additive.getRows()) || (getCols() != additive.getCols()) ) 	//if they are not the same size
    		cout<<"The matrices cannot be added because they are not the same size!"<<endl;
    	else {
    		Matrix sum(getRows(), getCols(), 'S');
    		for(int r=0;r<getRows();r++) 
    			for(int c=0;c<getCols();c++) 
    				sum.getTerms()[r][c] = getTerms()[r][c] + additive.getTerms()[r][c];
    		return sum;
    	}	//end else
    }	//END OPERATOR+
    Here there is the same problem in the if statement as operator=. But also, I thought I should not return a reference a because 1) a new matrix needs to be made and 2) I would be returning a reference to a local variable. But whenever I try to use the operator, the program stops working. How can I make this work? Any help is appreciated.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by SterlingM
    The problem here is that the compiler won't let me return 0. If the matrices are not the same size, I want the function (or whole program) to end there. How can I end the function?
    Throw an exception. Alternatively, you could turn this into a class template and have the size specified at compile time, in which case it would be a type error to assign to a matrix of different size.

    Quote Originally Posted by SterlingM
    Here there is the same problem in the if statement as operator=. But also, I thought I should not return a reference a because 1) a new matrix needs to be made and 2) I would be returning a reference to a local variable. But whenever I try to use the operator, the program stops working. How can I make this work?
    Yes, you have the right idea. Maybe the copy constructor has an incorrect implementation.

    By the way, unless you have special reasons for doing otherwise, the parameters of operator= and operator+ should be const references, and operator+ should be a const member function (or a non-member function).
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Oct 2009
    Posts
    117
    Ah! I forgot all about exceptions! And I'm pretty sure you're right about the copy constructor. I'll post it whenever I get it working if anyone else happens to read this and wants to know. Thanks.

  4. #4
    Registered User
    Join Date
    Oct 2009
    Posts
    117
    I have only made exception classes in Java so I'm unfamiliar with the details of it in C++. Whenever you call
    Code:
    runtime_error(const string&);
    Does that make a window pop-up telling you
    "Debug Error!
    Program: ...filename...
    This application has requested the Runtime to terminate it in an unusual way.
    Please contact the application's support team for more information."
    Then the abort, retry, ignore options?

    If so, I guess it's working correctly but not exactly how I'd like it to. If that sounds wrong, I can include some code. This only happens when I throw the exception. If the matrices are the same size, the program works fine.

  5. #5
    Registered User
    Join Date
    Oct 2009
    Posts
    117
    Okay well I'm pretty sure that window came up because instead of having a try..catch I just threw the exception. So I added a try..catch and the only problem is I'm not sure what to return in the function.

    Code:
    Matrix Matrix::operator+(const Matrix &additive) {
    	try {
    		if( (getRows() != additive.getRows()) || (getCols() != additive.getCols()) ) //if they are not the same size
    			throw DifferentSizeException();	//throw exception
    		else {
    			Matrix sum(getRows(), getCols(), 'S');
    			for(int r=0;r<getRows();r++) 
    				for(int c=0;c<getCols();c++) 
    					sum.getTerms()[r][c] = getTerms()[r][c] + additive.getTerms()[r][c];
    			return sum;
    		}	//end else
    	}	//end try
    	catch(DifferentSizeException &e) {
    		cout<<"The matrices cannot be added because they are not the same size."<<endl;
    	}	//end catch
    }	//END OPERATOR+
    See if the exception gets thrown, the function resumes and contains nothing else. At that point though, I DON'T want to return a matrix because the matrices should not be added.
    Last edited by SterlingM; 01-13-2010 at 02:35 AM. Reason: e to &e

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by SterlingM
    I have only made exception classes in Java so I'm unfamiliar with the details of it in C++.
    You can have your exception class inherit from std::exception (#include <exception>), but it is usually easier to derive from std::logic_error or std::runtime_error (#include <stdexcept>) since you only need to write a constructor that invokes the base class constructor when you do so.

    Okay well I'm pretty sure that window came up because instead of having a try..catch I just threw the exception.
    Yes, so a try/catch block is appropriate, but you should catch the exception by (const) reference.

    However, you are catching the exception in the same function that threw it. That is usually pointless. What you want to do is to just throw the exception so that the caller can handle it, e.g.,
    Code:
    Matrix Matrix::operator+(const Matrix &additive) const {
        if ( (getRows() != additive.getRows()) || (getCols() != additive.getCols()) ) {
            throw DifferentSizeException();
        }
    
        // Addition can be performed as the matrices have the same size.
        Matrix sum(getRows(), getCols(), 'S');
        for (int r = 0; r < getRows(); ++r) {
            for (int c = 0; c < getCols(); ++c) {
                sum.getTerms()[r][c] = getTerms()[r][c] + additive.getTerms()[r][c];
            }
        }
    
        return sum;
    }
    Incidentally, consider implementing operator+= as a member, and then you can implement operator+ as a non-member non-friend pretty easily:
    Code:
    Matrix& Matrix::operator+=(const Matrix& other) {
        if ( (getRows() != other.getRows()) || (getCols() != other.getCols()) ) {
            throw DifferentSizeException();
        }
    
        // Addition can be performed as the matrices have the same size.
        for (int r = 0; r < getRows(); ++r) {
            for (int c = 0; c < getCols(); ++c) {
                getTerms()[r][c] += other.getTerms()[r][c];
            }
        }
    
        return *this;
    }
    
    Matrix operator+(Matrix x, const Matrix& y) {
        return x += y;
    }
    If getRows(), getCols() and getTerms() are all public, you could actually implement both as non-member non-friend functions.
    Last edited by laserlight; 01-13-2010 at 02:43 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Registered User
    Join Date
    Oct 2009
    Posts
    117
    Awesome. Thanks for the information and advice. But one question - why would I want to make the operators non-member non-friend functions? What are the advantages (if it's not a super long list heh) over having them as member functions?

  8. #8
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by SterlingM
    Awesome. Thanks for the information and advice. But one question - why would I want to make the operators non-member non-friend functions? What are the advantages (if it's not a super long list heh) over having them as member functions?
    You could get a summary by reading an interview of Bjarne Stroustrup concerning The C++ Style Sweet Spot (in particular, the "Designing Simple Interfaces" section). Scott Meyers explains How Non-Member Functions Improve Encapsulation, and Herb Sutter dissects a negative example from the C++ standard library in GotW #84: Monoliths "Unstrung".
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #9
    Registered User
    Join Date
    Oct 2009
    Posts
    117
    Thank you for the help and especially the quick responses!

  10. #10
    Registered User
    Join Date
    Oct 2009
    Posts
    117
    This is off topic of the thread now I think but I have a quick question about making those functions non-member non-friend. I tried making them both non member non friend and the compiler gives me an error for each saying they have too many parameters. But if I make them friend functions they work fine.

    Code:
    class Matrix
    {
    	Matrix operator+=(Matrix &, const Matrix &);	//overload +=
    	Matrix operator+(Matrix &, const Matrix &);	//overload +
    	friend ostream &operator<<(ostream &, const Matrix &);	//printing matricies
    public:
    Code:
    Matrix operator+=(Matrix &additive1, const Matrix &additive2) {
    	if( (additive1.getRows() != additive2.getRows()) || (additive1.getCols() != additive2.getCols()) )
    		throw DifferentSizeException();
    	else {
    		for(int r=0;r<additive1.getRows();r++)
    			for(int c=0;c<additive1.getCols();c++)
    				additive1.getTerms()[r][c] += additive2.getTerms()[r][c];
    	}	//end else
    	return additive1;
    }	//END OPERATOR+=
    
    Matrix operator+(Matrix &additive1, const Matrix &additive2) {
    	return additive1 += additive2;
    }
    If I compile it like that I get the errors. But like I said, if I make the functions friends they work fine. Why is that?

  11. #11
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    It looks like you are trying to declare them as member functions even though you did not intend to do so.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  12. #12
    Registered User
    Join Date
    Oct 2009
    Posts
    117
    So...they would go in the file that my main function is in? Wouldn't that be bad for anyone wanting to reuse the Matrix class because they would have to implement the functions on their own instead of them being readily available?

  13. #13
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    No, they would be declared in the same header and namespace as your Matrix class, and you could implement them in the same source file that stores the implementation of the Matrix member functions.

    You might have a few convenience functions for Matrix that you wish to make optional, in which case you should declare them in the same namespace but in a different header file, and also implement them in a different source file.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  14. #14
    Registered User
    Join Date
    Oct 2009
    Posts
    117
    Well whenever I do that I get a ton (71 to be exact) of compiler errors. This is what I'm compiling for Matrix.h and Matrix.cpp.

    Code:
    #ifndef MATRIX_H
    #define MATRIX_H
    #pragma once
    #include <iostream>
    using std::ostream;
    using std::istream;
    
    
    Matrix &operator+=(Matrix &, const Matrix &);	//overload +=
    Matrix &operator+(Matrix &, const Matrix &);	//overload +
    
    class Matrix
    {
    	friend ostream &operator<<(ostream &, const Matrix &);	//printing matricies
    public:
    	Matrix(const Matrix &);
    	Matrix(int, int, char);
    	~Matrix(void);
    
    	void setTerms();	//puts terms into the matrix
    
    	//getter functions
    	char getName() const;
    	int getRows() const;
    	int getCols() const;
    	double **getTerms() const;
    
    
    	//overloaded operators
    	Matrix &operator=(const Matrix &);	//assignment operator
    	Matrix &operator*(double &);	//multiply matrix by a non-matrix
    	Matrix &operator*(Matrix &);	//multiple matrix by another matrix
    	//Matrix operator+(const Matrix &);		//add one matrix to another. DNR REFERENCE
    private:
    	double **terms;
    	int const rows;
    	int const cols;
    	char const name;
    };
    #endif
    Code:
    //MATRIX.CPP
    #include "Matrix.h"
    #include "DifferentSizeException.h"
    #include <iostream>
    using std::cout;
    using std::cin;
    using std::endl;
    #include <string>
    using std::string;
    
    
    Matrix &operator+=(Matrix &additive1, const Matrix &additive2) {
    	if( (additive1.getRows() != additive2.getRows()) || (additive1.getCols() != additive2.getCols()) )
    		throw DifferentSizeException();
    	else {
    		for(int r=0;r<additive1.getRows();r++)
    			for(int c=0;c<additive1.getCols();c++)
    				additive1.getTerms()[r][c] += additive2.getTerms()[r][c];
    	}	//end else
    	return additive1;
    }	//END OPERATOR+=
    
    Matrix &operator+(Matrix &additive1, const Matrix &additive2) {
    	return additive1 += additive2;
    }	//END OPERATOR+
    
    
    
    
    
    
    
    Matrix::Matrix(const Matrix &aMatrix) 
    : rows(aMatrix.getRows()), cols(aMatrix.getCols()), name(aMatrix.getName()) {
    	terms = new double *[rows];
    	for(int i=0;i<rows;i++)
    		*(terms+i) = new double[cols];	
    	for(int r=0;r<getRows();r++) 
    		for(int c=0;c<getCols();c++)
    			getTerms()[r][c] = aMatrix.getTerms()[r][c];
    
    }	//END COPY CONSTRUCTOR
    
    //constructor
    Matrix::Matrix(int r, int c, char n)
    : rows(r), cols(c), name(n) {
    	terms = new double *[getRows()];
    	for(int i=0;i<getRows();i++)
    		*(terms+i) = new double[cols];
    }	//END CONSTRUCTOR W/ NAME
    
    //destructor
    Matrix::~Matrix(void)
    { delete [] terms; }	//delete 2d array
    
    
    //GETTER FUNCTIONS
    char Matrix::getName() const {return name;}
    int Matrix::getRows() const {return rows;}
    int Matrix::getCols() const {return cols;}
    double **Matrix::getTerms() const {return terms;}
    //END GETTER FUNCTIONS
    
    //user inputs terms to be put into the matrix
    void Matrix::setTerms() {
    	cout<<"**********Matrix "<<getName()<<"**********"<<endl;
    	for(int r=0;r<rows;r++) {
    		for(int c=0;c<cols;c++) {
    			double theTerm;
    			cout<<"Enter the term for element ["<<r<<", "<<c<<"]."<<endl;
    			cin>>theTerm;
    			getTerms()[r][c] = theTerm;
    		}	//end inner for
    	}	//end double for
    }	//END SETTERMS()
    
    //print matrix
    ostream &operator<<(ostream &output, const Matrix &theMatrix) {
    	cout<<"--Matrix "<<theMatrix.getName()<<"--"<<endl;
    	for(int r = 0;r<theMatrix.getRows();r++) {
    		for(int c = 0;c<theMatrix.getCols();c++) {
    			output<<theMatrix.getTerms()[r][c]<<"\t";
    			if( (c+1) == theMatrix.getCols() ) 
    				output<<endl;
    		}	//end inner for
    	}	//end double for
    	return output;
    }	//END OPERATOR<<
    
    //assignment operator
    Matrix &Matrix::operator=(const Matrix &whatever) {
    	if(getRows() != whatever.getRows() || getCols() != whatever.getCols()) 
    		throw DifferentSizeException();
    	else {	//else if they are not the same size
    		for(int r=0;r<getRows();r++) 
    			for(int c=0;c<getCols();c++) 
    				getTerms()[r][c] = whatever.getTerms()[r][c];	//set the individual term
    	}	//end else
    	return *this;
    }	//END OPERATOR=
    
    //multiply matrix by a number 
    Matrix &Matrix::operator*(double &constant) {
    	for(int r=0;r<getRows();r++) 
    		for(int c=0;c<getCols();c++) 
    			getTerms()[r][c] *= constant;
    	return *this;
    }	//END OPERATOR*(DOUBLE)
    
    
    //Matrix Matrix::operator+(const Matrix &additive) {
    //		if( (getRows() != additive.getRows()) || (getCols() != additive.getCols()) ) //if they are not the same size
    //			throw DifferentSizeException();	//throw exception
    //		else {
    //			Matrix sum(getRows(), getCols(), 'S');
    //			for(int r=0;r<getRows();r++) 
    //				for(int c=0;c<getCols();c++) 
    //					sum.getTerms()[r][c] = getTerms()[r][c] + additive.getTerms()[r][c];
    //			return sum;	//return the sum
    //		}	//end else
    //}	//END OPERATOR+
    
    //TODO*********************************
    //multiply matrix by another matrix
    Matrix &Matrix::operator*(Matrix &secondFactor) {
    	return *this;
    }	//END OPERATOR*(MATRIX)
    I know most of that is unnecessary, but I'm including it just to show exactly what I'm compiling. I feel like I get the gist of what you're saying, but I'm slightly off. Declaring and implementing the operator functions where they are at is what I'm getting from what you said. What is wrong with it?

  15. #15
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Do not use using declarations or using directives at global or namespace scope in header files, or before including a file.

    Now, one possible problem lies with this member function:
    Code:
    double **getTerms() const;
    The problem is that you want to call it from a non-const reference to Matrix. You should actually use const overloading:
    Code:
    double** getTerms();
    const double* const * getTerms() const;
    By the way, your destructor does not correctly destroy the member array. It fails to destroy each dynamic array of double. Notice that my operator+ implementation takes the first argument by value, not by reference.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. why can't my perceptron learn correctly?
    By yann in forum C Programming
    Replies: 25
    Last Post: 10-15-2010, 12:26 AM
  2. unary operator overloading and classes
    By coletek in forum C++ Programming
    Replies: 9
    Last Post: 01-10-2009, 02:14 AM
  3. Smart pointer class
    By Elysia in forum C++ Programming
    Replies: 63
    Last Post: 11-03-2007, 07:05 AM
  4. Operator Overloading (Bug, or error in code?)
    By QuietWhistler in forum C++ Programming
    Replies: 2
    Last Post: 01-25-2006, 08:38 AM
  5. operator overloading and dynamic memory program
    By jlmac2001 in forum C++ Programming
    Replies: 3
    Last Post: 04-06-2003, 11:51 PM