今年的高程的C++试题向高手请教试题六
  阅读下列说明和C++程序,将应填入__(n)__处的字句写在答题纸的对应栏内.
[程序6说明]
  C++语言本身不提供对数组下标越界的判断.为了解决这一问题,在程序6中定义了相应的类模板,使得对于任意类型的二维数组,可以在访问数组元素的同时,对行下标和列下标进行越界判断,并给出相应的提示信息.
[程序6]
#include <iostream.h>
template <class T> class Array;
template <Class T> class ArrayBody {
 friend__(1)__;
 T* tpBody;
 int iRows,iColumns,iCurrentRow;
 ArrayBody(int iRsz,int iCsz){
  tpBody = __(2)__;
  iRows = iRsz;iColumns = iCsz;iCurrentRow = -1:
}
public;
 T& operator[](int j){
  bool row_error,column_error;
  row_error = column_error =false;
  try {
   if(iCurrentRow < 0 || iCurrentRow >= iRows)
    row_error = true;
   if(j<0 1,j>= iColumns)
    column_error = true;
   if(row_error == true || column_ error == true)
    __(3)__;
  }
  catch(char){
   if(row_error == true)
    cerr << "行下标越界[" << iCurrentRow << "]";
   if(column_error = true)
    cerr << "列下标越界[" << j << "]";
   cout << "\n";
  }
  return tpBody[iCurrentRow * iColumns + j];
 }
 ~Arraygody(){delete[]tpBody:}
};
template <class T> class Array {
 ArrayBody<T> tBody;
 public;
  ArrayBody<T> & operator[](int i) {
   __(4)__;
   return tBody;
  }
 Array(int iRsz,int iCsz):__(5)__ { }
 }; void main()
{
 Array<int> a1(10,20);
 Array<double> a2(3,5);
 int b1;
 double b2; ·
 b1 = a1[-5][10]; //有越界提示:行下标越界[-5]
 b1 = a1[10][15]; //有越界提示:行下标越界[10]
 b1 = a1[1][4];  //没有越界提示
 b2 = a2[2][6];  //有越界提示:列下标越界[6]
 b2 = a2[10][20]; //有越界提示;行下标越界[10]列下标越界[20]
 b2 = a2[1][4];  //没有越界提示
}
答案
试题六
  (1)classArray<T>
  (2)new T[iRsz*iCsz]
  (3)throw 'e'
  (4)tBody,iCurrentRow=i
  (5)tBody(iRsz,iCs2)问题如下:
在template <Class T> class ArrayBody中有一个操作符重载的函数
T& operator[](int j){
  bool row_error,column_error;
  row_error = column_error =false;
  try {
   if(iCurrentRow < 0 || iCurrentRow >= iRows)
    row_error = true;
   if(j<0 1,j>= iColumns)
    column_error = true;
   if(row_error == true || column_ error == true)
    __(3)__;
  }
  catch(char){
   if(row_error == true)
    cerr << "行下标越界[" << iCurrentRow << "]";
   if(column_error = true)
    cerr << "列下标越界[" << j << "]";
   cout << "\n";
  }
  return tpBody[iCurrentRow * iColumns + j];
 }在template <class T> class Array;中有一个函数叫什么我也说不好,我就想问这个函数与上边函数的关系,并且它在程序中怎么使用。ArrayBody<T> & operator[](int i) {
   __(4)__;
   return tBody;
  }谢谢各位了。

解决方案 »

  1.   

    这两个重载的操作符实现了像array[0][1]这样的操作。
    请看对于这样的一个两行两列的Array<int> myIntArray(2,2),对于这样的一个表达式myIntArray[1][2],它相当于(myIntArray.operator[](1)).operator[](2)。它的执行过程如下:
    首先调用Array<T>的[]操作符,它表示现在要访问这个数组的第1行,因此4的答案把Array<T>的成员tBody的iCurrentRow(当前要访问的行索引)设置为这个参数(这里是1)(因为在这里Array<T>要访问它的成员ArrayBody<T>类型的私有变量,所以有答案1),返回一个ArrayBody<T>&引用即Array<T>对象的成员tBody的引用;
    下一步也就是计算tBody.operator[](2)了。此时的tBody.iCurrentRow已在上一步中被赋值,由此值计算得到要访问的元素:参见ArrayBody<T>重载的[]可以得到,tBody的第1行第2列即tBody.tpBody[1 * iColumns + 2]。
      

  2.   

    这个重载了运算符[]通过array重载[]和ArrayBody的重载[]达到实现2维数组重载[][]假运算符的重载,并在函数里面做了判断,通过抛出异常的方法实现越界指示。当执行到 b1 = a1[-5][10]时先执行 value = a1[-5]也就是执行了Array中的ArrayBody<T> & operator[](int i)返回一个值赋给value,而后执行 a1[-5][10]也就是执行了value[10]等价于执行ArrayBody中的T& operator[](int j)进行行和列下标的判断。
      

  3.   

    一道题考到这么多C++内容:
    1、友元
    2、模板
    3、动态内存分配
    4、成员的初始化
    5、异常处理呵呵, bluwindhrt(风一飞) 兄 分析的透彻,关键是要理理解模板和[]操作符重载。
      

  4.   

    下面的函数返回一个上面函数的类型,在使用的时候,你可以这样理解:
    b1 = a1[1][4]; -> b1 = (a1[1])[4]; 
    首先,a1[1]返回一个ArryBody模板类的一个实例类的实例,下一个[4]返回该类的一个实例感觉你在程序中有些字符打错了,例如:
      (4)tBody,iCurrentRow=i
                -
      (4)tBody.iCurrentRow=i
                -
    这些字符很关键,会影响理解的!!!
      

  5.   

    bluwindhrt(风一飞) 和 xyking361(林梦怡) 的确是高手,他们短短两行话,绝对精典,说到了问题的实质,让我这个笨人看了整整一个小时,我现在已经明白程序运行的基本原理了,可还有一些问题请教一下,请指点:
    问题一:当执行到 b1 = a1[-5][10]时先执行 value = a1[-5]此时返回的是ArrayBody型的值,能讲一下tpBody指向的数组有多大?iRows,iColumns,iCurrentRow又分别是多少,是a1中的10*20那么大的数组吗?三个参数分别为10,20,-5对吗?
    问题二ArrayBody中的T& operator[](int j)是由谁在什么时候调用的。因为问题一中的调用是个重载函数,调用的是Array中的T& operator[](int j),而在ArrayBody的调用中我没有看出来什么地方用到了操作符[]。
    谢谢了
      

  6.   

    问题一:动态分配内存是发生在  Array<int> a1(10,20); Array<double> a2(3,5);这两句话,调用了构造函数分配了内存,所以tpBody指向的数组是10*20,和3*5,然后b1=a1[-5]这句话的目的是给iCurrentRow赋值,所以iCurrentRow=-5
    问题二;a1[-5]会返回一个tpbody的对象,然后下一个[10]就是调用ArrayBody中的T& operator[](int j),当时j=10.
      

  7.   

    问题二我能理解,第二个[]操作符调用的就是ArrayBody中的T& operator[](int j),
    但第一个问题我还是不能理解,当 new T[value] 中的value 是一个负数的话会发生什么样的事情?
    这个程序并没有作出适当的处理,这两个类的构造函数的参数应该是 unsigned int 吧.
      

  8.   

    问题一:
    iRows,iColumns,在a1被初始化时指定为10,20,并且在a1的整个生存期都是不变的,顾名思义,表示“数组”a1的行数和列数;iCurrentRow表示当前要访问的行,每一次调用Array<T>的[]操作符都会把它设置为调用的参数值。所以你的问题中都是对的。
    问题二:
    对于b1 = a1[-5][10],完全等同于下面合法的两行:
    ArrayBody<int>& temp = a1[-5];  //调用Array<int>的[]操作符,此时temp和a1.tBody是同一对象
    b1 = temp[10];                  //调用ArrayBody<int>的[]操作符
    对于砂子的问题:
    new操作符会抛出bad_alloc异常,当它无法分配需要的内存的时候。不过new[]操作符接受的参数类型为size_t,是unsigned int的typedef。不过我猜想如果你调用new int[-1]可能会异常抛出,因为-1会被强制类型转换为一个很大的正整数——大到可能根本无法分配这么大的空间给你哦(是2G的样子吧:P。所以在这里用unsigned int跟int是没有分别的。
      

  9.   

    仔细一想,还有一小问,题基本已经明白了,只是为了更透彻地掌握
    在ArrayBody<T> & operator[](int i) {
       __(4)__;
       return tBody;
      }
    对于b1 = a1[-5][10],return tBody 返回的值应当是
     数组大小为10*20那么,三个参数分别为10,20,-5对吧,可tBody是怎么得到的?是因为ArrayBody是它的友元,不是因为ArrayBody的构造函数已经给tBody的iRows和iColumns赋值,而tpBody->iCurrentRow=i,给iCurrentRow赋值了,换句话说友元有点继承的味道,这里的tBody与b2的是不同的(当然不同了),因为它们对应不同的ArrayBody,它是在什么时候被赋值的?
    即当b1确定,在任何时候它的tBody就已经确定了。不知我的理解正确吗。
      

  10.   

    tBody是如何得到iRows与iColumns这两个参数的呢?
    请看Array<T>的构造函数:
    Array(int iRsz,int iCsz):tBody(iRsz,iCs2){ }。
    正是在这里,Array<T>对象构造时,会将它的两个参数传给ArrayBody<T>的构造函数,从面构造Array<T>对象的成员tBody(请注意,在此处因为ArrayBody<T>的构造函数只有有参数的一个,所以必须用这种语法构造Array<T>对象。如果你对这种构造函数的定义语法不清楚,你得去看看更为详尽的C++语言基础了)。
    而对于iCurrentRow,这个成员是在每次调用Array<T>的[]操作符才赋值的,说白了,它其实只起到个临时变量的作用,跟对象的构造没什么关系。
    对于友元,它跟继承沾不上边(想想看:朋友跟父子有什么必然的联系吗?)。它只是跟访问有关。
    应该能注意到:ArrayBody<T>里所有的成员变量和构造函数都被声明成私有的。按理说,是不能在该类对象之外访问这些变量的,甚至根本无法构造一个ArrayBody<T>对象,因为它的构造函数都是不可访问的。但友元的存在使这种访问变得可能。
    请参看C++语言中关于友元的介绍吧。再啰嗦恐怕被人骂了:这些东西在上百本C++书里说得详细透彻百倍,你在这里磨什么牙呀!!呵呵!