c++编程练习 036:很难蒙混过关的CArray3d三维数组模板类

北大程序设计与算法(三)测验题汇总(2020春季)


描述

实现一个三维数组模版CArray3D,可以用来生成元素为任意类型变量的三维数组,输出指定结果

#include 
#include  
#include 
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. 必要时需重载对象到指针的强制类型转换运算符
    来源
    Guo Wei

分析

这道题,我也是根据提示做出来的,不然没有思路,因为只会二维的写法。a[i][j][k] 这个表达式的第一个[]返回一个内部类的对象,该内部类也重载了[],且返回值为指针。这句话诠释了我们该怎么做:

  1. 三维类的定义,先写外部定义
class CArray3D
{
public:
	T* p;
	int f, r, c; //数组共f层,每层r行,每行c列
	CArray3D(int _f, int _r, int _c) :f(_f), r(_r), c(_c) {
		p = new T[f * r * c];
	}
	~CArray3D() { delete[] p; }
};
  1. 然后是二维类的定义
class CArray2D {
	public:
		T* fp; // fp是一层的元素的起始地址
		int c; //数组每行c列
		T* operator[](int r) {
			return fp + r * c; //返回本层的第 r行起始地址		  
		}
		CArray2D(T* p_, int c_) :fp(p_), c(c_) { }
};		
  1. 下面是我们应该如何将这两个合并起来呢?根据思路来说,我们在定义内部对象的时候,应该要获得每一层的首地址,这样才能在内部类中再按照熟悉的二维方法书写。所以在三维类中还需要加一个调用二维的表达式,并且传值。那么传值肯定是构造函数啊:
CArray2D operator[](int _f) {//第_f层元素的起始地址
		return CArray2D(p + _f * r * c, c);
	}

那么这样就可以了,关键部分完成了,但是仅仅以上代码还是不行的,因为比如在以下地方:

	memset(a[1],-1 ,20*sizeof(int));	
	memset(a[1],-1 ,20*sizeof(int));

我们知道此时的a[1]是一个对象,是不能直接用于初始化的,那么,只有通过类型转换函数了:

operator T* () {
			return fp; //返回值本层的起始地址		  
}

将一个对象转换成T*类型即可顺利通过了。
完整的就是:

class CArray3D
{
public:
	T* p;
	int f, r, c; //数组共f层,每层r行,每行c列

	class CArray2D {
	public:
		T* fp; // fp是一层的元素的起始地址
		int c; //数组每行c列

		CArray2D(T* p_, int c_) :fp(p_), c(c_) { }
		T* operator[](int r) {
			return fp + r * c; //返回本层的第 r行起始地址		  
		}
		operator T* () {
			return fp; //返回值本层的起始地址		  
		}
	};
	CArray3D(int _f, int _r, int _c) :f(_f), r(_r), c(_c) {
		p = new T[f * r * c];
	}
	CArray2D operator[](int _f) {//第_f层元素的起始地址
		return CArray2D(p + _f * r * c, c);
	}
	~CArray3D() { delete[] p; }
};

你可能感兴趣的:(c++编程练习)