Lyt
posts - 16,comments - 61,trackbacks - 0

继前天凑动态多维数组失败后,经指导,终于将其实现。

把数组的维度一并放在模板里,而不用构造函数来实现,于是定义Array看起来像下边这样,其中NewArray是一个全局变量:

Array<int3> a=NewArrary[3][2][1];   //相当于int[3][2][1]

operator[] 是利用特化类模板来实现的:

template<typename _Type, int _DimensionCount>
class Array
{
private:
  _Type
* Elements;
  
int Size;
public:
  Array
<_Type, DimensionCount-1> operator[](const int Index);
}
;

template
<typename _Type>
class Array<_Type, 1>
{
private:
  _Type
* Elements;
  
int Size;
public:
  _Type
& operator[](const int Index);
  _Type 
operator[](const int Index)const;
}
;

在实现 Array<_Type, DimensionCount-1> operator[](const int Index) 时遇到一个问题,我需要返回一个Array<_Type, DimensionCount-1>,这个结果是根据当前的Array的信息来生成的,肯定需要用到private成员Elements,于是考虑用friend class Array<_Type, DimensionCount-1>,没想到编译器又喷我了,还是不能通过,原因不明T_T,无奈只能把Elements这些信息放到public下。

Array的测试用例如下:

#include "Library/UnitTest/UnitTest.h"
#include 
"Library/Basic/Array.h"

using namespace Lyt;

void InitArray(int* a, const int Size)
{
    
if (a)
    
{
        
for (int i=0; i<=Size-1; i++) a[i]=i;
    }

}


bool CheckArray(int* a1, int* a2, const int Size)
{
    
if (a1 && a2)
    
{
        
for (int i=0; i<=Size-1; i++)
            
if (a1[i]!=a2[i]) return false;
    }

    
else if (a1 || a2) return false;
    
return true;
}


TESTCASE(ArrayConstructorAssign, 
"ArrayConstructor")
{
    
int a[30];
    InitArray(a, 
30);
    
int dims[3];
    dims[
0]=2;
    dims[
1]=3;
    dims[
2]=5;

    Array
<int3> a1;
    EXPECT_TRUE(a1.Dimensions
!=0"DefaultConstructor");
    Array
<int3> a2=NewArray[2][3][5];
    InitArray(a2.Elements, a2.Size);
    EXPECT_TRUE(CheckArray(dims, a2.Dimensions, 
3&& CheckArray(a, a2.Elements, a2.Size), "NewArrayConstructor");
    Array
<int3> a3=a2;
    EXPECT_TRUE(CheckArray(dims, a3.Dimensions, 
3&& CheckArray(a, a3.Elements, a3.Size), "CopyConstructor");
    Array
<int2> a4=a3[1];
    EXPECT_TRUE(CheckArray(dims
+1, a4.Dimensions, 2&& CheckArray(a+15, a4.Elements, a4.Size), "CopyConstructor operator[]");
    Array
<int1> a5=a3[1][1];
    EXPECT_TRUE(CheckArray(dims
+2, a5.Dimensions, 1&& CheckArray(a+20, a5.Elements, a5.Size), "CopyConstructor operator[]");
    Array
<int1> a6=a5;
    EXPECT_TRUE(CheckArray(dims
+2, a6.Dimensions, 1&& CheckArray(a+20, a6.Elements, a6.Size), "CopyConstructor");

    EXPECT_TRUE(a2[
1][1][0]==20"operator[]");
    EXPECT_TRUE((a2[
1][1][0]=30)==30"operator=");
}


TESTCASE(ArrayAssign, 
"Array::operator=")
{
    
int a1[30];
    InitArray(a1, 
30);
    
int dims1[3];
    dims1[
0]=2;
    dims1[
1]=3;
    dims1[
2]=5;

    
int a2[8];
    InitArray(a2, 
8);
    
int dims2[3];
    dims2[
0]=2;
    dims2[
1]=2;
    dims2[
2]=2;

    Array
<int3> Array1=NewArray[2][3][5];
    InitArray(Array1.Elements, Array1.Size);
    Array
<int3> Array2=Array1;

    Array
<int3> Array3=NewArray[2][2][2];
    InitArray(Array3.Elements, Array3.Size);
    Array1
=Array3;
    EXPECT_TRUE(CheckArray(dims2, Array1.Dimensions, 
3&& CheckArray(a2, Array1.Elements, Array1.Size), "operator=");
    EXPECT_TRUE(Array1[
0][1][1]==3"operator[]");

    Array
<int2> Array4=Array1[0];
    Array
<int1> Array5=Array1[0][1];
    Array5[
1]=9;
    EXPECT_TRUE(Array1[
0][1][1]==9 && Array3[0][1][1]==9 && Array4[1][1]==9"operator=");

    Array3
=Array2;
    EXPECT_TRUE(CheckArray(dims1, Array3.Dimensions, 
3&& CheckArray(a1, Array3.Elements, Array3.Size), "operator=");
}


TESTCASE(ArrayClone, 
"Array::Clone")
{
    
int a[30];
    InitArray(a, 
30);
    
int dims[3];
    dims[
0]=2;
    dims[
1]=3;
    dims[
2]=5;

    Array
<int3> a1=NewArray[2][3][5];
    InitArray(a1.Elements, a1.Size);
    Array
<int3> a2=a1.Clone();
    EXPECT_TRUE(CheckArray(dims, a2.Dimensions, 
3&& CheckArray(a, a2.Elements, a2.Size), "Clone");
    a1[
0][0][0]=100;
    EXPECT_TRUE(a1[
0][0][0]==100 && a2[0][0][0]==0"operator=");
}

Array源码:

#ifndef ARRAY_H
#define ARRAY_H

#include 
<memory.h>

namespace Lyt
{
    template
<int _DimensionCount>
    
class ArrayDimension
    
{
    
public:
        
int Data[_DimensionCount+1];

        ArrayDimension()
        
{
            
for (int i=0; i<=_DimensionCount-1; i++) Data[i]=0;
        }


        ArrayDimension(
const int Dimension, int* PrevDimensions)
        
{
            Data[_DimensionCount
-1]=Dimension;
            memcpy(Data, PrevDimensions, 
sizeof(int)*(_DimensionCount-1));
        }


        ArrayDimension
<_DimensionCount+1> operator[](const int Dimension)
        
{
            
return ArrayDimension<_DimensionCount+1>(Dimension, Data);
        }


        
int GetSize()const
        
{
            
int Result=1;
            
for (int i=0; i<=_DimensionCount-1; i++) Result*=Data[i];
            
return Result;
        }

    }
;

    
extern ArrayDimension<0> NewArray; 

    template
<typename _Type, int _DimensionCount>
    
class Array
    
{
    
protected:
        
void RefIncrease()
        
{
            
if (RefCount) (*RefCount)++;
        }


        
void RefDecrease()
        
{
            
if (RefCount)
            
{
                
if (--(*RefCount)==0)
                
{
                    delete RefCount;
                    delete[] (Dimensions
-DimensionsIndex);
                    
if (Elements) delete[] (Elements-ElementsIndex);
                    RefCount
=0;
                    Dimensions
=0;
                    Elements
=0;
                    Size
=0;
                    ElementsIndex
=0;
                    DimensionsIndex
=0;
                }

            }

        }

    
    
public:
        
int* RefCount;
        
int* Dimensions;
        _Type
* Elements;
        
int Size;
        
int ElementsIndex;
        
int DimensionsIndex;

        Array()
        
{
            RefCount
=new int(1);
            Dimensions
=new int[_DimensionCount];
            Elements
=0;
            Size
=0;
            ElementsIndex
=0;
            DimensionsIndex
=0;
        }


        Array(
const Array<_Type, _DimensionCount>& Object)
        
{
            RefCount
=Object.RefCount;
            Dimensions
=Object.Dimensions;
            Elements
=Object.Elements;
            Size
=Object.Size;
            ElementsIndex
=Object.ElementsIndex;
            DimensionsIndex
=Object.DimensionsIndex;
            RefIncrease();
        }


        Array(
const ArrayDimension<_DimensionCount> Dims)
        
{
            RefCount
=new int(1);
            Dimensions
=new int[_DimensionCount];
            memcpy(Dimensions, Dims.Data, 
sizeof(int)*_DimensionCount);
            Size
=Dims.GetSize();
            Elements
=new _Type[Size];
            ElementsIndex
=0;
            DimensionsIndex
=0;
        }


        
~Array()
        
{
            RefDecrease();
        }


        Array
<_Type, _DimensionCount>& operator=(const Array<_Type, _DimensionCount>& Object)
        
{
            RefDecrease();
            RefCount
=Object.RefCount;
            Dimensions
=Object.Dimensions;
            Elements
=Object.Elements;
            Size
=Object.Size;
            ElementsIndex
=Object.ElementsIndex;
            DimensionsIndex
=Object.DimensionsIndex;
            RefIncrease();
            
return *this;
        }


        Array
<_Type, _DimensionCount-1> operator[](const int Index)
        
{
            RefIncrease();
            Array
<_Type, _DimensionCount-1> Result;
            delete Result.RefCount;
            Result.RefCount
=RefCount;
            Result.Size
=Size/Dimensions[0];
            Result.Dimensions
=Dimensions+1;
            Result.Elements
=Elements+Index*Result.Size;
            Result.ElementsIndex
=ElementsIndex+Index*Result.Size;
            Result.DimensionsIndex
=DimensionsIndex+1;
            
return Result;
        }


        Array
<_Type, _DimensionCount> Clone()const
        
{
            Array
<_Type, _DimensionCount> Result;
            memcpy(Result.Dimensions, Dimensions, 
sizeof(int)*(_DimensionCount));
            Result.Size
=Size;
            Result.Elements
=new _Type[Size];
            memcpy(Result.Elements, Elements, 
sizeof(int)*(Size));
            
return Result;
        }

    }
;

    template
<typename _Type>
    
class Array<_Type, 1>
    
{
    
protected:
        
void RefIncrease()
        
{
            
if (RefCount) (*RefCount)++;
        }


        
void RefDecrease()
        
{
            
if (RefCount)
            
{
                
if (--(*RefCount)==0)
                
{
                    delete RefCount;
                    delete[] (Dimensions
-DimensionsIndex);
                    
if (Elements) delete[] (Elements-ElementsIndex);
                    RefCount
=0;
                    Dimensions
=0;
                    Elements
=0;
                    Size
=0;
                    ElementsIndex
=0;
                    DimensionsIndex
=0;
                }

            }

        }

    
    
public:
        
int* RefCount;
        
int* Dimensions;
        _Type
* Elements;
        
int Size;
        
int ElementsIndex;
        
int DimensionsIndex;

        Array()
        
{
            RefCount
=new int(1);
            Dimensions
=new int[1];
            Elements
=0;
            Size
=0;
            ElementsIndex
=0;
            DimensionsIndex
=0;
        }


        Array(
const Array<_Type, 1>& Object)
        
{
            RefCount
=Object.RefCount;
            Dimensions
=Object.Dimensions;
            Elements
=Object.Elements;
            Size
=Object.Size;
            ElementsIndex
=Object.ElementsIndex;
            DimensionsIndex
=Object.DimensionsIndex;
            RefIncrease();
        }


        Array(
const ArrayDimension<1> Dims)
        
{
            RefCount
=new int(1);
            Dimensions
=new int[];
            memcpy(Dimensions, Dims.Data, 
sizeof(int));
            Size
=Dims.GetSize();
            Elements
=new _Type[Size];
            ElementsIndex
=0;
            DimensionsIndex
=0;
        }


        
~Array()
        
{
            RefDecrease();
        }


        Array
<_Type, 1>& operator=(const Array<_Type, 1>& Object)
        
{
            RefDecrease();
            RefCount
=Object.RefCount;
            Dimensions
=Object.Dimensions;
            Elements
=Object.Elements;
            Size
=Object.Size;
            ElementsIndex
=Object.ElementsIndex;
            DimensionsIndex
=Object.DimensionsIndex;
            RefIncrease();
            
return *this;
        }


        _Type
& operator[](const int Index)
        
{
            
if (Index<0 || Index>=Dimensions[0]) throw L"越界访问";
            
else return Elements[Index];
        }


        _Type 
operator[](const int Index)const
        
{
            
if (Index<0 || Index>=Dimensions[0]) throw L"越界访问";
            
else return Elements[Index];
        }


        Array
<_Type, 1> Clone()const
        
{
            Array
<_Type, 1> Result;
            mencpy(Result.Dimensions, Dimensions, 
sizeof(int));
            Result.Size
=Size;
            Result.Elements
=new _Type[Size];
            memcpy(Result.Elements, Elements, 
sizeof(int)*(Size));
            
return Result;
        }

    }
;
}


#endif
欢迎各位继续喷~
posted on 2009-10-13 14:16 Lyt 阅读(1488) 评论(9)  编辑 收藏 引用 所属分类: 数据结构

FeedBack:
# re: 很傻很天真之Array——解决方法
2009-10-13 16:34 | 远古毛利人
楼主可以参考一下boost::multiarray的实现  回复  更多评论
  
# re: 很傻很天真之Array——解决方法
2009-10-13 17:32 | 陈梓瀚(vczh)
应该是让Array的构造函数接受多一点东西才对,而不是把什么都放到public里面。  回复  更多评论
  
# re: 很傻很天真之Array——解决方法
2009-10-13 17:38 | 陈梓瀚(vczh)
而且你的Array<i>想用Array<i-1>的时候,应该在Array<i>里面friend那个Array<i+1>才对,怎么能friend那个Array<-1>呢,你搞反了。  回复  更多评论
  
# re: 很傻很天真之Array——解决方法
2009-10-13 20:11 | 陈昱(CY)
很强大,接下来应该实现tuple了  回复  更多评论
  
# re: 很傻很天真之Array——解决方法
2009-10-14 11:38 | 欲三更
再来个迭代器吧, 这样就能方便使用那些算法了.  回复  更多评论
  
# re: 很傻很天真之Array——解决方法
2009-10-14 16:22 | 暗涌
不错,学习了
另外:
Array<_Type, 1> Clone()const
{
Array<_Type, 1> Result;
mencpy(Result.Dimensions, Dimensions, sizeof(int)); // memcpy笔误了
Result.Size=Size;
Result.Elements=new _Type[Size];
memcpy(Result.Elements, Elements, sizeof(int)*(Size));
return Result;
}

  回复  更多评论
  
# re: 很傻很天真之Array——解决方法
2009-10-14 16:37 | 暗涌
lz,我用friend class Array<_Type, _DimensionCount-1>是可以的哦,但是要记住在特化的Array里面也要加friend class Array<_Type, 0>  回复  更多评论
  
# re: 很傻很天真之Array——解决方法
2009-10-14 16:40 | 伊莎贝儿女装
是的数据库反反复复反反复复  回复  更多评论
  
# re: 很傻很天真之Array——解决方法
2009-10-14 16:44 | 暗涌
@暗涌
Sorry, 之前没有做访问操作,确实不行,用+1也不行  回复  更多评论
  

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理