一个类来管理多维数组! 我怎样才能做到在细胞来管理不同类型的数据?(A class to man

2019-10-22 22:42发布

我声明,我是一个C程序员不是一个C ++程序员更多的(与C ++我是个初学者:P)

我已经写了一个C ++类来管理多维阵列(n维矩阵)。 这个类有方法来创建矩阵和设置,并获得价值/从基体(也设置里面的位置)。

我有两个问题:

  • 有了,我想类似米语法的想法(X,Y,Z,...,n)的设置/获取值的一些方法使用省略号EG:的getValue(INT DIM0,...); 但我认为这是危险的; 虽然我写我假定传递的参数是相同数量的矩阵的各个维度的功能,用户可能超过必要使更少的数值,那么他将没有编译器错误或警告。

  • 我想能够管理,矩阵细胞矩阵在创建时运行期间包含(不使用工会并以某种方式宣布型)的数据类型。 在类代码中,我插一个typedef(用于开发目的),它指明了这样的修改会/可能会影响点。

对于第一个问题,我没有想法比实现要好。 你有什么建议?

为了解决第二个问题,我可能想为方法创建的getValue)重载(,的setValue()和createMatrix(),但这个想法需要一些变通方法,并可能完全重写每一个单一的方法,然后有更多的副本“同样的”代码(我想避免的意图有更好的维修能力),而且这种解决方案并不授予管理所有可能的类型。 我正在考虑使用模板,但如果这种方式是更好的办法,我不明白。 你有什么建议?

这些都是进行修改,以解决这两个问题的方法主要有:

在CPP模块的方法:

int Matrix::createMatrix(Matrix::value_t *values)
{
    int retval=1;

    if ( (m_values!=NULL || !numOfDim()) && valAreIntAlloc()==true ) {
        return 0;
    }

    if (values!=NULL) {
        m_values=values;
        setValAreIntAlloc(false);
    } else {
        setValAreIntAlloc(true);
        // Compute the number of elements for
        // the whole matrix
        for(int i=0;i<numOfDim();i++) {
            retval*=numOfElemInDim(i);
            if (!retval) {
                //Indicate that a dimension has a 0 value
                //as numOfElemInDim! The caller will be allowed
                //to know the such a dimension using: -retval-1;
                retval=-(i+1);
                break;
            }
        }
        if (retval>0) {
            m_values=new value_t[retval];
            if (m_values!=NULL)
                retval=0;
        }
    }

    //Returns:
    //1 if values is an external allocated memory,
    //0 if nothing has been allocated or the
    //m_values is already set as internal!
    //elsewhere the number of allocated elements.
    return retval;
}

void Matrix::setPositions(int dim0, ...)
{
    va_list vl;
    va_start(vl,dim0);

    setPosition(0,dim0);
    for (int i=1;i<numOfDim();i++)
        setPosition(i,va_arg(vl,int));

    va_end(vl);
}

Matrix::value_t Matrix::getValue(int dim0, ...)
{
    va_list vl;
    va_start(vl,dim0);

    setPosition(0,dim0);
    for (int i=1;i<numOfDim();i++)
        setPosition(i,va_arg(vl,int));

    va_end(vl);
    return getValue();
}

void Matrix::setValue(Matrix::value_t value, int dim0, ...)
{
    va_list vl;
    va_start(vl,dim0);

    setPosition(0,dim0);
    for (int i=1;i<numOfDim();i++)
        setPosition(i,va_arg(vl,int));

    va_end(vl);
    setValue(value);
}

方法内联在头文件中:

inline value_t getValue() { return m_values[posInValueVector()]; }

inline void setValue(value_t value) { m_values[posInValueVector()]=value; }

所述方法的setPosition(),setPositions()用于设置要被管理的所述基质细胞的坐标; 该方法posInValueVector()计算向量使用的坐标的矩阵单元的(通过该方法createMatrix创建)内的索引。

这里人的代码:

main.cpp中

#include <iostream>
#include <cstdio>

#include "matrix.h"

using namespace std;

int main()
{
    Matrix m(3);
    m.setNumOfElemInDims(4,5,6);
    m.createMatrix();

    for(int i=0;i<m.numOfElemInDim(0);i++)
        for(int j=0;j<m.numOfElemInDim(1);j++)
            for(int k=0;k<m.numOfElemInDim(2);k++)
                m.setValue(i*100+j*10+k,i,j,k); // matrix(i,j,k)=i*100+j*10+k

    //printout the values of all matrix(i,j,k) cells
    //I've used the printf because I find it very simple!
    for(int i=0;i<m.numOfElemInDim(0);i++)
        for(int j=0;j<m.numOfElemInDim(1);j++)
            for(int k=0;k<m.numOfElemInDim(2);k++)
                printf("(%d,%d,%d)=%03.0f\n",i,j,k,m.getValue(i,j,k));
}

matrix.h

#ifndef MATRIX_H
#define MATRIX_H

class Matrix
{
public:
    typedef double value_t;

    Matrix();
    Matrix(int numOfDim, int *nelem=NULL);
    ~Matrix();

    inline unsigned int numOfDim() const {return m_numOfDim;}

    int setNumOfDim(int numOfDim, int *nelem=NULL);

    inline  int numOfElemInDim(int dim) const
        {return (dim<numOfDim())?m_numOfElemInDim[dim]:-1; }

    int setNumOfElemInDim(int dim, int nelem);
    int setNumOfElemInDims(int el0, ...);

    int createMatrix(value_t *values);
    inline int createMatrix() { return createMatrix(NULL); }

    inline bool valAreIntAlloc() const {return m_valAreIntAlloc;}
    inline void setValAreIntAlloc(bool valAreIntAlloc)
        {m_valAreIntAlloc = valAreIntAlloc;}

    inline int position(int dim) const {return m_positions[dim];}
    inline void setPosition(int dim,int value)
        {m_positions[dim] = value;}

    inline void setPositions(int *positions)
        {for(int i=0;i<numOfDim();i++) setPosition(i,positions[i]);}

    void setPositions(int dim0, ...);

    inline value_t getValue() { return m_values[posInValueVector()]; }

    value_t getValue(int dim0, ...);

    inline void setValue(value_t value) { m_values[posInValueVector()]=value; }
    void setValue(value_t value, int dim0, ...);

private:
    int m_numOfDim;
    int * m_numOfElemInDim;
    int * m_positions;

    value_t * m_values;
    bool m_valAreIntAlloc;

    int posInValueVector();
};

#endif // MATRIX_H

matrix.cpp

#include <iostream>
#include <cstdarg>

#include "matrix.h"

#define __INIT__(v)\
m_numOfDim(v),\
m_numOfElemInDim(NULL),\
m_positions(NULL),\
m_values(NULL),\
m_valAreIntAlloc(false)

Matrix::Matrix():
    __INIT__(0)
{
}

Matrix::~Matrix()
{
    if (m_numOfElemInDim!=NULL)
        delete m_numOfElemInDim;

    if (m_positions!=NULL)
        delete m_positions;

    if (valAreIntAlloc() && m_values!=NULL)
        delete m_values;
}

Matrix::Matrix(int numOfDim, int *nelem):
    __INIT__(numOfDim)
{
    setNumOfDim(numOfDim,nelem);
}

int Matrix::setNumOfDim(int numOfDim, int *nelem)
{
    int retval=0;

    m_numOfDim = numOfDim;

    m_numOfElemInDim = new int[numOfDim];
    if (m_numOfElemInDim==NULL)
        return 1;

    m_positions = new int[numOfDim];
    if (m_positions==NULL)
        return 2;

    for(int i=0;i<m_numOfDim;i++) {
        if (setNumOfElemInDim(i,(nelem==NULL)?0:nelem[i])) {
            retval=-1;
            break;
        }
        setPosition(i,0);
    }

    return retval; //All ok!
}

int Matrix::setNumOfElemInDim(int dim,int nelem)
{
    int retval=-1;

    if (dim<numOfDim()) {
        m_numOfElemInDim[dim] = nelem;
        retval=0;
    }

    return retval;
}

int Matrix::setNumOfElemInDims(int el0, ...)
{
    va_list vl;
    va_start(vl,el0);

    setNumOfElemInDim(0,el0);
    for (int i=1;i<numOfDim();i++)
        setNumOfElemInDim(i,va_arg(vl,int));

    va_end(vl);
    return 0;
}

int Matrix::createMatrix(Matrix::value_t *values)
{
    int retval=1;

    if ( (m_values!=NULL || !numOfDim()) && valAreIntAlloc()==true ) {
        return 0;
    }

    if (values!=NULL) {
        m_values=values;
        setValAreIntAlloc(false);
    } else {
        setValAreIntAlloc(true);
        // Compute the number of elements for
        // the whole matrix
        for(int i=0;i<numOfDim();i++) {
            retval*=numOfElemInDim(i);
            if (!retval) {
                //Indicate that a dimension has a 0 value
                //as numOfElemInDim! The caller will be allowed
                //to know the such a dimension using: -retval-1;
                retval=-(i+1);
                break;
            }
        }
        if (retval>0) {
            m_values=new value_t[retval];
            if (m_values!=NULL)
                retval=0;
        }
    }

    //Returns:
    //1 if values is an external allocated memory,
    //0 if nothing has been allocated or the
    //m_values is already set as internal!
    //elsewhere the number of allocated elements.
    return retval;
}

void Matrix::setPositions(int dim0, ...)
{
    va_list vl;
    va_start(vl,dim0);

    setPosition(0,dim0);
    for (int i=1;i<numOfDim();i++)
        setPosition(i,va_arg(vl,int));

    va_end(vl);
}

Matrix::value_t Matrix::getValue(int dim0, ...)
{
    va_list vl;
    va_start(vl,dim0);

    setPosition(0,dim0);
    for (int i=1;i<numOfDim();i++)
        setPosition(i,va_arg(vl,int));

    va_end(vl);
    return getValue();
}

void Matrix::setValue(Matrix::value_t value, int dim0, ...)
{
    va_list vl;
    va_start(vl,dim0);

    setPosition(0,dim0);
    for (int i=1;i<numOfDim();i++)
        setPosition(i,va_arg(vl,int));

    va_end(vl);
    setValue(value);
}

int Matrix::posInValueVector()
{
    int pos=position(0);

    for(int i=1;i<numOfDim();i++)
        pos=pos*numOfElemInDim(i)+position(i);

    return pos;
}

Answer 1:

I think the solution below, that is an answer at another my question, is a beautiful solution and implements all what I wanted, but I used a lot of code ... It's based on C++11 variadic templates.

A dubt I've about this code is the way in whose it manages the memory. My will would be the memory is a single block, I'm almost sure this code don't do that. However is a good and fast code!

template<typename T, int ...rest>
struct matrix;

template<typename T, int n>
struct matrix<T, n> {
    T data[n];
    matrix() {
        for (int i=0; i<n; i++) {
            data[i] = T(0);
        }
    }
    T& operator[](int index) { return data[index]; }
};

template<typename T, int n, int ...rest>
struct matrix<T, n, rest...> {
    matrix<T, rest...> data[n];
    matrix<T, rest...>& operator[](int index) { return data[index]; }
};

that can be used with:

matrix<double, 10, 9, 4> m;
for (int i=0; i<10; i++) {
    for (int j=0; j<9; j++) {
        for (int k=0; k<4; k++) {
            m[i][j][k] = i + j*2.718 + k*3.1416;
        }
    }
}


Answer 2:

我已经找到了解决办法,但我不完全喜欢它!

我已经修改了createMatrix(),的getValue()和的setValue()方法和插在两个限定与省略号完成的功能。 当时的想法是使用模板。 下面是我想他们是模板的定义:

#define __MATRIX_GETVALUE(C,T,val,dim0...) \
    va_list vl; \
    va_start(vl,dim0); \
    C->setPositions(vl,dim0); va_end(vl);\
    val = *((T *)(m_values)+posInValueVector())

#define __MATRIX_SETVALUE(C,T,val,dim0...) \
    va_list vl; \
    va_start(vl,dim0); \
    C->setPositions(vl,dim0); va_end(vl);\
    *((T *)(m_values)+posInValueVector())=val

在下面的修改后的代码:

main.cpp中

#include <iostream>
#include <cstdio>

#include "matrix.h"

using namespace std;

int main()
{
    Matrix m(3);
    m.setNumOfCellForDims(4,5,6);

    puts("-----------------> DBL m(i,j,k)=i*100+j*10+k+111 -------------------");
    m.createMatrix(sizeof(double));
    for(int i=0;i<m.numOfCellInDim(0);i++)
        for(int j=0;j<m.numOfCellInDim(1);j++)
            for(int k=0;k<m.numOfCellInDim(2);k++)
                m.setValue((double)i*100+j*10+k+111,i,j,k); // matrix(i,j,k)=i*100+j*10+k

    //printout the values of all matrix(i,j,k) cells
    double valdbl;
    for(int i=0;i<m.numOfCellInDim(0);i++)
        for(int j=0;j<m.numOfCellInDim(1);j++)
            for(int k=0;k<m.numOfCellInDim(2);k++)
                printf("(%d,%d,%d)=%03.0f\n",i,j,k,m.getValue(valdbl,i,j,k));

    puts("-----------------> INT m(i,j,k)=i*100+j*10+k+222 -------------------");
    m.clearMatrix();
    m.setNumOfDim(3);
    m.setNumOfCellForDims(4,5,6);
    m.createMatrix(sizeof(int));

    for(int i=0;i<m.numOfCellInDim(0);i++)
        for(int j=0;j<m.numOfCellInDim(1);j++)
            for(int k=0;k<m.numOfCellInDim(2);k++)
                m.setValue((int)(i*100+j*10+k+222),i,j,k); // matrix(i,j,k)=i*100+j*10+k

    //printout the values of all matrix(i,j,k) cells
    int valint;
    for(int i=0;i<m.numOfCellInDim(0);i++)
        for(int j=0;j<m.numOfCellInDim(1);j++)
            for(int k=0;k<m.numOfCellInDim(2);k++)
                printf("(%d,%d,%d)=%03d\n",i,j,k,m.getValue(valint,i,j,k));
}

matrix.h

#ifndef MATRIX_H
#define MATRIX_H
#include <cstdarg>
#include <cstring>

#define __MATRIX_GETVALUE(C,T,val,dim0...) \
    va_list vl; \
    va_start(vl,dim0); \
    C->setPositions(vl,dim0); va_end(vl);\
    val = *((T *)(m_values)+posInValueVector())

#define __MATRIX_SETVALUE(C,T,val,dim0...) \
    va_list vl; \
    va_start(vl,dim0); \
    C->setPositions(vl,dim0); va_end(vl);\
    *((T *)(m_values)+posInValueVector())=val

class Matrix
{
public:
    Matrix();
    Matrix(int numOfDim, int *ncell=NULL);
    ~Matrix();

    void clearMatrix();

    inline unsigned int numOfDim() const {return m_numOfDim;}

    int setNumOfDim(int numOfDim, int *ncell=NULL);

    inline  int numOfCellInDim(int dim) const
        {return (dim<numOfDim())?m_numOfCellInDim[dim]:-1; }

    int setNumOfCellForDim(int dim, int ncell);
    int setNumOfCellForDims(int el0, ...);

    int createMatrix(int size, void *values);
    inline int createMatrix(int size) { return createMatrix(size,NULL); }

    inline bool valAreIntAlloc() const {return m_valAreIntAlloc;}
    inline void setValAreIntAlloc(bool valAreIntAlloc)
        {m_valAreIntAlloc = valAreIntAlloc;}

    inline int position(int dim) const {return m_positions[dim];}
    inline void setPosition(int dim,int value)
        {m_positions[dim] = value;}

    inline void setPositions(int *positions)
        {for(int i=0;i<numOfDim();i++) setPosition(i,positions[i]);}

    void setPositions(int dim0, ...);

    inline void * getValue() { return (char *)m_values+posInValueVector(); }

    inline double getValue(double &value)
    { return value=*(double *)(m_values)+posInValueVector(); }

    inline int getValue(int &value)
    { return value=*(int *)(m_values)+posInValueVector(); }

    //void * getValue(int dim0, ...);
    inline double getValue(double &value, int dim0, ...) {
        __MATRIX_GETVALUE(this,double,value,dim0);
        return value;
    }

    inline int getValue(int &value, int dim0, ...) {
        __MATRIX_GETVALUE(this,int,value,dim0);
        return value;
    }

    inline void setValue(double value)
        { *((double *)(m_values)+posInValueVector())=value; }
    inline void setValue(int value)
        { *((int *)(m_values)+posInValueVector())=value; }
    inline void setValue(void *value, int size)
        { memcpy((char *)m_values+posInValueVector(),(char *)value,size); }

    //void setValue(double value, int dim0, ...);
    inline void setValue(double value, int dim0, ...) {
        __MATRIX_SETVALUE(this,double,value,dim0);
    }
    inline void setValue(int value, int dim0, ...) {
        __MATRIX_SETVALUE(this,int,value,dim0);
    }

    inline int cellSize() const {return m_cellSize;}
    inline void setCellSize(int cellSize) {m_cellSize = cellSize;}

private:
    int m_numOfDim;
    int m_cellSize;

    int * m_numOfCellInDim;
    int * m_positions;

    void * m_values;
    bool m_valAreIntAlloc;

    int posInValueVector();

#ifdef MATRIX_CPP
    inline
#endif
    int setPositions(va_list &vl, const int &dim0);
};

#endif // MATRIX_H

matrix.cpp

#define MATRIX_CPP
#include <iostream>

#include "matrix.h"

#define __INIT__(v)\
m_numOfDim(v),\
m_cellSize(0), \
m_numOfCellInDim(NULL),\
m_positions(NULL),\
m_values(NULL),\
m_valAreIntAlloc(false)

Matrix::Matrix():
    __INIT__(0)
{
}

Matrix::~Matrix()
{
    clearMatrix();
}

void Matrix::clearMatrix()
{
    if (m_numOfCellInDim!=NULL)
        delete m_numOfCellInDim;
    m_numOfCellInDim=NULL;

    if (m_positions!=NULL)
        delete m_positions;
    m_positions=NULL;

    if (valAreIntAlloc() && m_values!=NULL)
        delete (char *)m_values;
    m_values=NULL;
}

Matrix::Matrix(int numOfDim, int *ncell):
    __INIT__(numOfDim)
{
    setNumOfDim(numOfDim,ncell);
}

int Matrix::setNumOfDim(int numOfDim, int *ncell)
{
    int retval=0;

    m_numOfDim = numOfDim;

    m_numOfCellInDim = new int[numOfDim];
    if (m_numOfCellInDim==NULL)
        return 1;

    m_positions = new int[numOfDim];
    if (m_positions==NULL)
        return 2;

    for(int i=0;i<m_numOfDim;i++) {
        if (setNumOfCellForDim(i,(ncell==NULL)?0:ncell[i])) {
            retval=-1;
            break;
        }
        setPosition(i,0);
    }

    return retval; //All ok!
}

int Matrix::setNumOfCellForDim(int dim,int ncell)
{
    int retval=-1;

    if (dim<numOfDim()) {
        m_numOfCellInDim[dim] = ncell;
        retval=0;
    }

    return retval;
}

int Matrix::setNumOfCellForDims(int el0, ...)
{
    va_list vl;
    va_start(vl,el0);

    setNumOfCellForDim(0,el0);
    for (int i=1;i<numOfDim();i++)
        setNumOfCellForDim(i,va_arg(vl,int));

    va_end(vl);
    return 0;
}

int Matrix::createMatrix(int size, void *values)
{
    int retval=1;

    setCellSize(size);

    if ( (m_values!=NULL || !numOfDim()) && valAreIntAlloc()==true ) {
        return 0;
    }

    if (values!=NULL) {
        m_values=values;
        setValAreIntAlloc(false);
    } else {
        setValAreIntAlloc(true);
        // Compute the number of cellents for
        // the whole matrix
        for(int i=0;i<numOfDim();i++) {
            retval*=numOfCellInDim(i);
            if (!retval) {
                //Indicate that a dimension has a 0 value
                //as numOfCellInDim! The caller will be allowed
                //to know the such a dimension using: -retval-1;
                retval=-(i+1);
                break;
            }
        }
        if (retval>0) {
            m_values=new char[retval*cellSize()];
            if (m_values!=NULL)
                retval=0;
        }
    }

    //Returns:
    //1 if values is an external allocated memory,
    //0 if nothing has been allocated or the
    //m_values is already set as internal!
    //elsewhere the number of allocated cellents.
    return retval;
}

void Matrix::setPositions(int dim0, ...)
{
    va_list vl;
    va_start(vl,dim0);

    setPositions(vl,dim0);
    va_end(vl);
}

int Matrix::setPositions(va_list &vl,const int &dim0)
{
    setPosition(0,dim0);
    for (int i=1;i<numOfDim();i++)
        setPosition(i,va_arg(vl,int));
}

int Matrix::posInValueVector()
{
    int pos=position(0);

    for(int i=1;i<numOfDim();i++)
        pos=pos*numOfCellInDim(i)+position(i);

    return pos;
}


文章来源: A class to manage multidimensional array! How can I do to manage different data types in the cells?