07:很难蒙混过关的CArray3d三维数组模板类
描述
实现一个三维数组模版CArray3D,可以用来生成元素为任意类型变量的三维数组,输出指定结果
#include <iostream>
#include <iomanip>
#include <cstring>
using namespace std;
template <class T>
class CArray3D
{//此处填充代码
};CArray3D<int> a(3,4,5);
CArray3D<double> b(3,2,2);
void PrintA()
{for(int i = 0;i < 3; ++i) {cout << "layer " << i << ":" << endl;for(int j = 0; j < 4; ++j) {for(int k = 0; k < 5; ++k) cout << a[i][j][k] << "," ;cout << endl;}}
}
void PrintB()
{for(int i = 0;i < 3; ++i) {cout << "layer " << i << ":" << endl;for(int j = 0; j < 2; ++j) {for(int k = 0; k < 2; ++k) cout << b[i][j][k] << "," ;cout << endl;}}
}int main()
{int No = 0;for( int i = 0; i < 3; ++ i ) {a[i];for( int j = 0; j < 4; ++j ) {a[j][i];for( int k = 0; k < 5; ++k )a[i][j][k] = No ++;a[j][i][i]; }}PrintA();memset(a[1],-1 ,20*sizeof(int)); memset(a[1],-1 ,20*sizeof(int));PrintA(); memset(a[1][1],0 ,5*sizeof(int)); PrintA();for( int i = 0; i < 3; ++ i )for( int j = 0; j < 2; ++j )for( int k = 0; k < 2; ++k )b[i][j][k] = 10.0/(i+j+k+1);PrintB();int n = a[0][1][2];double f = b[0][1][1];cout << "****" << endl;cout << n << "," << f << endl;return 0;
}
输入
无
输出
等同于样例
样例输入
无
样例输出
layer 0: 0,1,2,3,4, 5,6,7,8,9, 10,11,12,13,14, 15,16,17,18,19, layer 1: 20,21,22,23,24, 25,26,27,28,29, 30,31,32,33,34, 35,36,37,38,39, layer 2: 40,41,42,43,44, 45,46,47,48,49, 50,51,52,53,54, 55,56,57,58,59, layer 0: 0,1,2,3,4, 5,6,7,8,9, 10,11,12,13,14, 15,16,17,18,19, layer 1: -1,-1,-1,-1,-1, -1,-1,-1,-1,-1, -1,-1,-1,-1,-1, -1,-1,-1,-1,-1, layer 2: 40,41,42,43,44, 45,46,47,48,49, 50,51,52,53,54, 55,56,57,58,59, layer 0: 0,1,2,3,4, 5,6,7,8,9, 10,11,12,13,14, 15,16,17,18,19, layer 1: -1,-1,-1,-1,-1, 0,0,0,0,0, -1,-1,-1,-1,-1, -1,-1,-1,-1,-1, layer 2: 40,41,42,43,44, 45,46,47,48,49, 50,51,52,53,54, 55,56,57,58,59, layer 0: 10,5, 5,3.33333, layer 1: 5,3.33333, 3.33333,2.5, layer 2: 3.33333,2.5, 2.5,2, **** 7,3.33333
提示
建议做法:
1. a[i][j][k] 这个表达式的第一个[]返回一个内部类的对象,该内部类也重载了[],且返回值为指针。
2. 必要时需重载对象到指针的强制类型转换运算符
解题分析
要想实现一个三维数组类,如果只是要求存储一些数据,并且通过a[i][j][k]运算符去取出数据,那么我们直接用循环和new操作符即可,但是注意这样得到的三维数组是个假三维数组,它的内存并不是连续存储的,而是分多块存储,这并不符合本题的要求,也不能直接用memset去操作超出分配的内存的一整片连续空间。
template <class T>
class CArray3D
{// 在此处补充你的代码T*** Array;int x,y,z;
public:CArray3D(int a,int b,int c) : x{a},y{b},z{c}{Array = new T**[a];for(int i=0;i<b;i++){Array[i] = new T*[b];for(int j=0;j<c;j++){Array[i][j] = new T[c];}}}T** operator[](int i){return Array[i];}};
所以正确的做法是啥子类?首先,C/C++里面真正的数组内存都是连续的,那我们创建一个T *Array; 然后初始化时分配一整片三维数组需要的连续的内存,这个肯定没问题。那我们怎么做到a[i][j][k]三个运算符的重载呢? 分析一下,最后一个[k]运算后我们希望是T 那么第二个[j]运算后我们希望是T*,也就是说第一个[i]运算后我们希望得到T**?这显然不是一件容易的事情。
换个思路,我们不妨这样去想,如果是一个二维数组,我们要分配一个连续的内存空间并且满足上述[]运算符要求,是不是很简单?
template<class T>
class CArray2D {friend class CArray3D<T>;private:T* data;int Y, Z;public:CArray2D() : data(nullptr), Y(0), Z(0) {}void allocate(int y, int z) {Y = y; Z = z;data = new T[Y * Z]();}T* operator[](int y) {return data + y * Z;}const T* operator[](int y) const {return data + y * Z;}operator T*(){return data;}~CArray2D() {delete[] data;}};
注意,这里的强制类型转换函数是为了迎合memset!
所以最后代码就是这样的~
template <class T>
class CArray3D {
public:class CArray2D {friend class CArray3D<T>;private:T* data;int Y, Z;public:CArray2D() : data(nullptr), Y(0), Z(0) {}void allocate(int y, int z) {Y = y; Z = z;data = new T[Y * Z]();}T* operator[](int y) {return data + y * Z;}const T* operator[](int y) const {return data + y * Z;}operator T*(){return data;}~CArray2D() {delete[] data;}};private:CArray2D* array2D;int X;public:CArray3D(int x, int y, int z) : X(x) {array2D = new CArray2D[X];for (int i = 0; i < X; ++i) {array2D[i].allocate(y, z);}}CArray2D& operator[](int x) {return array2D[x];}const CArray2D& operator[](int x) const {return array2D[x];}~CArray3D() {delete[] array2D;}
};