How to define a new class "Matrix" based on "Vector<Vector<T>>"?

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • herbu
    New Member
    • Apr 2010
    • 5

    How to define a new class "Matrix" based on "Vector<Vector<T>>"?

    In order to automatically check if the index of an array declared by vector<T> exceeding its boundary, we define the class "Vector" derived from "vector" and do the operator overloading as shown in Vector.h. And it works well.
    However, when we need to use the 2-dimensional array, we need to write more than 5 lines in order to initialize the 2-D array, as shown in main.cpp.

    My question is: is there any way to define a new class "Matrix" which enjoys the ability of "Vector" for automatically checking the array boundary. and its declaration and initialization could be as simple as:

    Matrix<double> tmp;
    tmp.assignName( "tmp", 3, 4, 0.00);

    -----------------------------------------------------
    Many thanks for the helps.

    "Vector.h" and "main.cpp" could be seen in tmp.zip.

    Best regards,
    Herbu.
    Attached Files
  • akdemirc
    New Member
    • Sep 2008
    • 26

    #2
    perhaps you can think of Matrix class having a member variable of type Vector<Vector<T >> rather than deriving it from Vector<Vector<T >> which makes your matrix code as follows:

    Code:
    #include "Vector.h"
    
    #ifndef _MATRIX
    
    #define _MATRIX
    
    using namespace std;
    
    
    template <class   T>   
    class Matrix {   
    public:   
    	Matrix();   
    	void setName(char *matrixName);
    	void showName();
    	void assignName(char *vectorName, int xSize, int ySize, T initialValue);
    	void print();
    private:
    	char nameOfMatrix[100];
    	Vector<Vector<T>> bitErrCntCI;
    };   
    
    template <class T>
    Matrix<T>::Matrix()
    {
    
    }
    
    template <class T>
    void Matrix<T>::setName(char *matrixName) 
    {    
    	if(strlen(matrixName) >= 100) {
    		printf("Error: %s is more than 100 characters, please increase the size of nameOfMatrix[] in Matrix.h\n", vectorName);
    		getchar();
    		exit(1);
    	} else {
    		strcpy_s(nameOfMatrix, matrixName);
    	}
    }
    
    template <class T>
    void Matrix<T>::showName()
    {
    	printf("The name of the matrix is %s\n", nameOfMatrix);
    }
    
    
    template <class T>
    void Matrix<T>::assignName(char *vectorName, int xSize, int ySize, T initialValue)
    {
    	if(strlen(vectorName) >= 100) {
    		printf("Error: %s is more than 100 characters, please increase the size of nameOfVector[] in Vector.h\n", vectorName);
    		getchar();
    		exit(1);
    	} else {
    		strcpy_s(nameOfMatrix, vectorName);
    	}
    
    	char tmpChar[100];
    	int err_sprintf;
    	bitErrCntCI.resize(xSize);
    	for(int snrIdx = 0;snrIdx < xSize ;snrIdx++)
    	{
    		err_sprintf = sprintf_s(tmpChar, 100,"bitErrCntCI[%d]", snrIdx);
    		if(err_sprintf == -1) {
    			printf("Error: sprintf_s for bitErrCntCI[] in main.cpp is wrong.\n");
    			getchar();
    			exit(1);
    		}
    
    		bitErrCntCI.at(snrIdx).assignName(tmpChar, ySize, initialValue);
    	}
    }
    
    
    #endif

    Comment

    • herbu
      New Member
      • Apr 2010
      • 5

      #3
      Many thanks Akdemirc,

      But in this way, I could not use the object of "Matrix" just like a regular 2-dimensional array. For example, to access the matrix as

      Matrix tmp;
      tmp.assignName( "tmp", 3, 4, 0.00);

      for(int rowIdx = 0;rowIdx < 3;rowIdx++) {
      for(int colIdx = 0;colIdx < 4;colIdx++) {
      tmp[rowIdx][colIdx] = input[rowIdx][colIdx];
      }
      }

      I had seen codes which could do this but I forget how it is achieved. Any suggestions?

      Best regards,
      Herbu.

      Comment

      • Banfa
        Recognized Expert Expert
        • Feb 2006
        • 9067

        #4
        I agree about have your data held internally rather than deriving from it however I say why hold it as Vector<Vector<T >>. Just hold a Vector<T> of the right size of all entries in the matrix, so 9 for a 3 x 3 matrix for example.

        It is a common mistake to always try and make the internal data representation of a class match what it makes available on the public interface and it is entirely unnecessary. Hold the data in the esiest way to hold the data design your interface to give calling the the interface you require.

        As to
        Code:
        Matrix tmp;
        tmp.assignName("tmp", 3, 4, 0.00);
        
        for(int rowIdx = 0;rowIdx < 3;rowIdx++) {
            for(int colIdx = 0;colIdx < 4;colIdx++) {
                tmp[rowIdx][colIdx] = input[rowIdx][colIdx];
            }
        }
        are you sure you can't be happy with a member function something like

        Code:
                tmp.at(rowIdx,colIdx) = input.at(rowIdx,colIdx);
        you could even overload operator() for


        Code:
                tmp(rowIdx,colIdx) = input(rowIdx,colIdx);
        However if you insist on

        Code:
                tmp[rowIdx][colIdx] = input[rowIdx][colIdx];
        The trick is to have operator[] return a class representing a row in the matrix that is a friend of the matrix class which also implments operator[].

        Comment

        • akdemirc
          New Member
          • Sep 2008
          • 26

          #5
          adding two similar member functions to matrix class as you have in vector seems to do what you want:

          declaration:
          Code:
          	Vector<T> &operator[] (int);
          	const Vector<T> &operator[] (int) const;

          definition:

          Code:
          template <class T>
          Vector<T> &Matrix<T>::operator[] (int idx) 
          {
          	if(idx < 0 || idx >= bitErrCntCI.size()) {
          		printf("Error: trying to access %s[%d] exceed [0, %d].\n", nameOfMatrix, idx, bitErrCntCI.size()-1);
          		getchar();
          		exit(1);
          	}
          	// printf("size = %d \n", size());
          	return bitErrCntCI.at(idx);
          }
          
          template <class T>
          const Vector<T> &Matrix<T>::operator[](int idx) const
          {
          	if(idx < 0 || idx >= bitErrCntCI.size()) {
          		printf("Error: trying to access %s[%d] exceed [0, %d].\n", nameOfMatrix, idx, bitErrCntCI.size()-1);
          		getchar();
          		exit(1);
          	}
          	return bitErrCntCI.at(idx);
          }

          Comment

          • herbu
            New Member
            • Apr 2010
            • 5

            #6
            Originally posted by akdemirc
            adding two similar member functions to matrix class as you have in vector seems to do what you want:

            declaration:
            Code:
            	Vector<T> &operator[] (int);
            	const Vector<T> &operator[] (int) const;

            definition:

            Code:
            template <class T>
            Vector<T> &Matrix<T>::operator[] (int idx) 
            {
            	if(idx < 0 || idx >= bitErrCntCI.size()) {
            		printf("Error: trying to access %s[%d] exceed [0, %d].\n", nameOfMatrix, idx, bitErrCntCI.size()-1);
            		getchar();
            		exit(1);
            	}
            	// printf("size = %d \n", size());
            	return bitErrCntCI.at(idx);
            }
            
            template <class T>
            const Vector<T> &Matrix<T>::operator[](int idx) const
            {
            	if(idx < 0 || idx >= bitErrCntCI.size()) {
            		printf("Error: trying to access %s[%d] exceed [0, %d].\n", nameOfMatrix, idx, bitErrCntCI.size()-1);
            		getchar();
            		exit(1);
            	}
            	return bitErrCntCI.at(idx);
            }
            Thanks akdemirc,

            However, with this, when declare
            Matrix<double> tmp;
            tmp.assignName( "tmp", 3, 4, 0.00);

            When trying to
            "tmp[-1][0] = 1.00;" we could see the error message due to operator loading
            "template <class T>
            Vector<T> &Matrix<T>::ope rator[] (int idx) "

            However, it could not check "tmp[0][-1] = 1.00;".
            Actually, the operator overloading "template <class T>
            const Vector<T> &Matrix<T>::ope rator[](int idx) const " is not effective.

            Does anyone know the difference between these two operator overloading?
            1. template <class T>
            Vector<T> &Matrix<T>::ope rator[] (int idx)
            2. template <class T>
            const Vector<T> &Matrix<T>::ope rator[](int idx) const

            Best regards,
            Herbu.

            Comment

            • akdemirc
              New Member
              • Sep 2008
              • 26

              #7
              However, it could not check "tmp[0][-1] = 1.00;" is not completely true i think.. As you have boundary checks in Vector class and the -1 index is passes as parameter to Vector class' [] operator, it is the Vector class that should control the validity of this parameter.

              Comment

              • herbu
                New Member
                • Apr 2010
                • 5

                #8
                Originally posted by akdemirc
                However, it could not check "tmp[0][-1] = 1.00;" is not completely true i think.. As you have boundary checks in Vector class and the -1 index is passes as parameter to Vector class' [] operator, it is the Vector class that should control the validity of this parameter.
                Thanks Akdemirc,

                Yes, it is my fault to forget "#define CHECK_VECTOR_IN DEX" such that the operator overloading in "Vector" is not activated. After defining CHECK_VECTOR_IN DEX, "tmp[0][-1] = 1.00" would be checked.

                However, do you know the meaning of "const T &operator[] (int) const;"
                I learned this from a slides which said it is used to check the boundary when the array is at the right-hand-side of the equality. But this function just does not respond to any input.

                Best regards,
                Herbu.

                Comment

                • akdemirc
                  New Member
                  • Sep 2008
                  • 26

                  #9
                  const T &operator[] (int) const; declaration tells that this function returns a const reference of type T that cannot be modified (that make the return value only a r-value) and the const statement at the end tells us that the function guarantees not to modify any of the members of the class.

                  Comment

                  • herbu
                    New Member
                    • Apr 2010
                    • 5

                    #10
                    Thanks again, akdemirc,

                    Now I am clearer at the newly defined class. I slightly revise the codes
                    on Vector.h. It would be very much apprepciated in case I could learn your opinions on the revised codes.

                    Vector.h (ps: When need to activate the function of checking index of array/matrix boundary, we need to define the flag CHECK_VECTOR_IN DEX.)
                    Code:
                    #include <iostream>
                    #include <stdio.h>
                    #include <string.h>
                    #include <stdio.h>
                    #include <math.h>
                    #include <stdlib.h>
                    #include <malloc.h>
                    #include <string>
                    #include <vector>
                    
                    // #define CHECK_VECTOR_INDEX
                    
                    #ifndef _VECTOR
                    #define _VECTOR
                    
                    using namespace std;
                    
                    template <class   T>   
                    class Vector : public vector<T>{   
                    	public:   
                    		Vector();   
                    		void setName(char *vectorName);
                    		void showName();
                    		void assignName(char *vectorName, int vectorSize, T initialValue);
                    		#ifdef CHECK_VECTOR_INDEX
                    		T &operator[] (int);
                    		const T &operator[] (int) const;
                    		#endif
                    	private:
                    		char nameOfVector[100];
                    };   
                    
                    template <class T>
                    Vector<T>::Vector()
                    {
                    	
                    }
                    
                    template <class T>
                    void Vector<T>::setName(char *vectorName) 
                    {    
                    	if(strlen(vectorName) >= 100) {
                    		printf("Error: %s is more than 100 characters, please increase the size of nameOfVector[] in Vector.h\n", vectorName);
                    		getchar();
                    		exit(1);
                    	} else {
                    		strcpy_s(nameOfVector, vectorName);
                    	}
                    }
                    
                    template <class T>
                    void Vector<T>::showName()
                    {
                    	printf("The name of the vector is %s\n", nameOfVector);
                    }
                    
                    template <class T>
                    void Vector<T>::assignName(char *vectorName, int vectorSize, T initialValue)
                    {
                    	if(strlen(vectorName) >= 100) {
                    		printf("Error: %s is more than 100 characters, please increase the size of nameOfVector[] in Vector.h\n", vectorName);
                    		getchar();
                    		exit(1);
                    	} else {
                    		strcpy_s(nameOfVector, vectorName);
                    	}
                    
                    	assign(vectorSize, initialValue);
                    }
                    
                    #ifdef CHECK_VECTOR_INDEX
                    template <class T>
                    T &Vector<T>::operator[] (int idx) 
                    {
                    	if(idx < 0 || idx >= size()) {
                    		printf("Error: trying to access %s[%d] exceed [0, %d].\n", nameOfVector, idx, size()-1);
                    		getchar();
                    		exit(1);
                    	}
                    	return at(idx);
                    }
                    
                    template <class T>
                    const T &Vector<T>::operator[](int idx) const
                    {
                    	if(idx < 0 || idx >= size()) {
                    		printf("Error: trying to access %s[%d] exceed [0, %d].\n", nameOfVector, idx, size()-1);
                    		getchar();
                    		exit(1);
                    	}	
                    	return at(idx);
                    }
                    #endif
                    
                    #endif
                    // -------------------------------    Define Class 2-dimensional vector (i.e. Matrix)   ------------------------------- 
                    #ifndef _MATRIX   
                    #define _MATRIX 
                      
                    using namespace std; 
                      
                    template <class   T>    
                    class Matrix {    
                    	public:    
                    		Matrix();
                    		void setName(char *matrixName);
                    		void showName();
                    		void assignName(char *vectorName, int xSize, int ySize, T initialValue);
                    		Vector<T> &operator[] (int); 
                    		const Vector<T> &operator[] (int) const; 
                    	private: 
                    		char nameOfMatrix[100];
                    		
                    		Vector< Vector<T> > internalVector;
                    		Vector<int> tmp;
                    		int rowSize;
                    		int columnSize;
                    };    
                      
                    template <class T> 
                    Matrix<T>::Matrix() 
                    { 
                    	rowSize = 0;
                    	columnSize = 0;
                    } 
                      
                    template <class T> 
                    void Matrix<T>::setName(char *matrixName)  
                    {     
                        if(strlen(matrixName) >= 100) { 
                            printf("Error: %s is more than 100 characters, please increase the size of nameOfMatrix[] in Matrix.h\n", vectorName); 
                            getchar(); 
                            exit(1); 
                        } else { 
                            strcpy_s(nameOfMatrix, matrixName); 
                        } 
                    } 
                      
                    template <class T> 
                    void Matrix<T>::showName() 
                    { 
                        printf("The name of the matrix is %s\n", nameOfMatrix); 
                    } 
                      
                    template <class T> 
                    void Matrix<T>::assignName(char *vectorName, int xSize, int ySize, T initialValue) 
                    {
                    	char tmpChar[100];
                    	int err_sprintf; 
                    	if(strlen(vectorName) >= 100) {
                    		printf("Error: %s is more than 100 characters, please increase the size of nameOfVector[] in Vector.h\n", vectorName);
                    		getchar();
                    		exit(1);
                    	} else {
                    		strcpy_s(nameOfMatrix, vectorName);
                    	}
                    	rowSize = xSize;
                    	columnSize = ySize;
                    	internalVector.resize(xSize);
                    	internalVector.setName(vectorName);
                    
                    	for(int snrIdx = 0;snrIdx < xSize ;snrIdx++) {
                    		err_sprintf = sprintf_s(tmpChar, 100,"%s[%d]", vectorName, snrIdx);
                    		if(err_sprintf == -1) {
                    			printf("Error: sprintf_s for %s[] in assignName of Matrix is wrong.\n", vectorName);
                    			getchar();
                    			exit(1);
                    		}
                    		internalVector.at(snrIdx).assignName(tmpChar, ySize, initialValue);
                    	} 
                    } 
                    
                    
                    template <class T> 
                    Vector<T> &Matrix<T>::operator[] (int idx)  
                    {
                    	#ifdef CHECK_VECTOR_INDEX
                    	if(idx < 0 || idx >= rowSize) {
                    		printf("Error: try to access %s[%d] exceed [0, %d].\n", nameOfMatrix, idx, rowSize-1);
                    		getchar();
                    		exit(1);
                    	}
                    	#endif
                    
                    	return internalVector.at(idx); 
                    } 
                      
                    template <class T> 
                    const Vector<T> &Matrix<T>::operator[](int idx) const 
                    { 
                    	#ifdef CHECK_VECTOR_INDEX
                    	if(idx < 0 || idx >= rowSize) {
                    		printf("Error: try to access %s[%d] exceed [0, %d].\n", nameOfMatrix, idx, rowSize-1);
                    		getchar();
                    		exit(1);
                    	}
                    	#endif
                    	
                    	return internalVector.at(idx); 
                    }
                    #endif
                    Best regards,
                    Herbu.

                    Comment

                    • akdemirc
                      New Member
                      • Sep 2008
                      • 26

                      #11
                      Herbu,

                      The code looks pretty good that make it hard for me to give advice:) Perhaps you can think of removing the member variable tmp of type Vector in Matrix class which i can not see any usage of it.. Besides adding a print method both for Vector and Matrix class may be helpful in using them.. print method of Vector can simply print all elements it holds, while Matrix's print method iterates and calls the member vector's elements' print method and adding a newline at the end of each..

                      Best Regards,
                      akdemirc

                      Comment

                      Working...