一个管理多维数组的类!如何管理单元格中的不同数据类型?

Posted

技术标签:

【中文标题】一个管理多维数组的类!如何管理单元格中的不同数据类型?【英文标题】:A class to manage multidimensional array! How can I do to manage different data types in the cells? 【发布时间】:2015-05-02 23:34:23 【问题描述】:

我声明我是 C 程序员而不是 C++ 程序员(使用 C++ 我是初学者:p)

我编写了一个 C++ 类来管理多维数组(n 维矩阵)。此类具有创建矩阵以及在矩阵中/从矩阵中设置和获取值的方法(也可以设置其中的位置)。

我有两个问题:

我希望使用类似于 m(x,y,z, ..., n) 的语法来设置/获取值,一些方法使用省略号例如: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));

矩阵.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

矩阵.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;

【问题讨论】:

也许通过使用Boost variant 或Boost any? 在这段代码中我不使用 boost!我对boost没有很好的了解。你认为我可以用它来解决我指出的问题吗? 你可以使用非类型模板参数来设置所需参数的数量,或者如果太复杂的话,至少在运行时断言它们是正确的。 另一个对我来说不太清楚的论点!我要研究模板!!! @OMGtechy,您的意思是使用这样的模板我可以获得用户不能使用错误数量的参数吗? @SergioFormiggini 是的 【参考方案1】:

我认为下面的解决方案,即我的另一个问题的answer,是一个漂亮的解决方案,实现了我想要的所有东西,但我使用了很多代码......它基于 C++11 可变参数模板.

我对这段代码的质疑是它管理内存的方式。我的意愿是内存是一个块,我几乎可以肯定这段代码不会那样做。不过是一个又好又快的代码!

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]; 
;

可用于:

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;
        
    

【讨论】:

使用模板类型定义会更好。只需将您的matrix 更改为matrix_impl - 并且不要在其中定义任何操作。仅类型:template &lt;typename T, int n&gt; struct matrix_impl&lt;T,n&gt; using type = T[n]; ;template &lt;typename T, int n, int ...t&gt; struct matrix_impl&lt;T,n,r...&gt; using type = typename T&lt;T,r...&gt;::type[n]; ; 类型定义:template &lt;typename T, int ...n&gt; using matrix=typename matrix_impl&lt;T,n...&gt;::type; 我是这类对象(模板)的新手!我是 C 程序员而不是 C++ 程序员,我能够使用 C++ 编写代码,但我需要学习很多东西才能理解模板!那我不明白你提议的好处,可能是因为对我来说还不是很清楚我提议的模板(那不是我写的代码) 我在想这个:“我的意愿是内存是一个单独的块”,这样你就可以确定 - 因为Matrix&lt;T,1,2,3&gt; 将等同于T[1][2][3]...跨度> 【参考方案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));

矩阵.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

矩阵.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;

【讨论】:

以上是关于一个管理多维数组的类!如何管理单元格中的不同数据类型?的主要内容,如果未能解决你的问题,请参考以下文章

在表视图内的集合视图中传递多维数组

带有Swift的多个自定义单元格的UITableview

通过在一个单元格中输入公式来填充不同单元格的数组公式

如何在 iOS 中管理自定义单元格标签值?

如何在 numberofitemsinsection 中管理两个不同的单元格

在TableViewController中将排序数据管理到索引部分和单元格中