您的位置:首页 > 其它

TxtMonster的设计过程(一)

2005-04-20 19:07 162 查看
上次的作业刚刚做完,还没来得及总结,下一个作业又来了,真是苦恼呀!先来说说问题的描述:

[描述]

设计一个类,它能接收数据流(现水平可以用接收键盘输入来代替),数据流中会有换行符,每个新行的前导和后导空格要去除,接收到的数据流要保留,可以随时输出所有已经接收到的数据(要求分行显示),也要能按提供的行号随机输出。[输入]

         abc

           def

         gh  ij

         kl  (最后含两个空格,注)

         mno            (还没有回车换行,注)

[输出]

         abc

         def

         gh  ij

         kl      (末尾这两个空格不输出,注)

/**************************************/

 

这个题目看上去不是很难嘛,呵呵。

这个题目我要解决下面几个问题:

1、接收到的数据的保存。 按道理是要存放在文件中的,可我现在还不会文件操作,我待解决的问题还有很多,文件操作先暂放一放。我打算使用一个结构变量或类来存放所有的接收到的数据。可以采用链表来存储。我打算使用下面图所示的结构:


说明:我使用surface,line,point(面,线,点)来形容这个结构,为的是好记。

我的想法是,每次有字符压进来,就放在最左边的line中,最上面的是最近(新)的。遇到换行符,生成新的line接在最左侧。

我想,这样肯定是可以完成老师的作业的,这之所以这样做还有一个原因,就是我想利用这个结构,使自己对于指针的操作进一步熟练,我也不能判断这样做带来的后果是有益的还是有害的,也许应该使用字符数组,但我想,那样的话,存放字串的数组要设计多大是一个问题,大了可能会造成大量的浪费,小了就可能放不下了(当然我们可以在结构中放一些flag说明这个串有没有结束),我所不清楚的是,这种设计无论是在读还是在写的时候会有大量的指针运动,这会降低效率吗?真希望高手指点。不过我想,就是用数组的话,说不定我们在输出数组的时候,内部也是这样的大量指针运动的(呵呵,我不清楚)。

2、我在想的一个问题是:我设计了三个结构体,他们相扣在一起形成存放字符流的结构,这个结构中会有很多的小对象,这些对象的成员是不是应该设计成私有的?下面我还是把几个struct预写一下(什么叫预写?呵呵,我发明的,就是草稿的意思嘛)。

struct point                //存储一个字符的点

{

     char c;

     point* next;

};

 

struct line                      //存储一个串的线,带头结点

{

     point* head;

     line* next;

};

 

struct surface                   //存储整个树的面,带头结点

{

     line* head;

};

 

//然后再设计一个类,当中就使用了这个结构。

class CtxtMonster                //这个类还没设计完成,起个头

{

private:

     surface txt_tree;

     int PrintLine(point*);     

public:

     CTxtMonster();

     ~CTxtMonster();

     int InputChar(char);        //向Monster压入一个字符

     int OutputLine(int);        //参数表示要求输出的行号,以1开始

     int OutputSurface();        //输出整个结构

int Reset();                //重置整个对象

};

 

大家可能注意到了,这个类中的我所谓的surface结构其实就是一个指针,我倒是想,这好像是一个公主的帽子,外面挂了好多的垂珠,晃晃当当的,看上去感觉一点也不聚合。总使我产生封装差的感觉。有一点我不明白,我将txt_tree这个surface结构声明成了private,那组成这个txt_tree的三个结构会不会封装得很好呢?等写完这个程序后一定要研究研究这个问题,这里暂时先放一下。(呵呵,眼睛一眨,都有两个问题放一下了,呵呵)

一、int PrintLine(point*);的实现

    int CTxtMonster::PrintLine(point* pMe)

{

          if(pMe->next!=NULL)

               PrintLine(pMe->next);

          cout<<pMe->c;

}

说明:这是向屏幕输出一个字串,向函数传递的是line的第一个point的地址。

采用的是递归方法,这样第一个输出的应该是最下面的字符,那个字符又是第一个压进去的,正好符合顺序。

二、int InputChar(char); 的实现

int CTxtMonster::InputChar(char nosh)

{

         point* pNosh;

          pNosh=new point;

          pNosh->c=nosh;

          pNosh->next=Null;

         ……      (这里是将上面的pNosh插入,略)

          return 0;

}

说明:这是向整个结构中传入字符。这里有一个问题,就是:我们要不要判断这个传入的字符的种类,根据不同的各类做出不同的处理?比如看是不是换行符,要是的话就产生新的line,看看是不是新一行的开始的空格,是不是重复的换行等等,如果不判断也是可以的,但这个小函数就应该变成一个内部private函数,专门用来延长line结构。采用哪一种方法呢?还是用专职的吧!因为我们写的函数应该尽量功能专一,这样函数的XX性小一点(呵呵,这里有一个词忘记了,好像是什么内聚,偶联什么的,呵呵,真是不好意思)。那么我们得做一点小的修改,将名字改成:private:  int ProlongLine(char);

这样的话,这个函数要做的事是:

1、   产生一个point;

2、   用参数初始化它;

3、   把它连入相应的line;

我想应该就这么多事情吧。好了,把这段再复制过来修改一下:

int CTxtMonster::ProlongLine(char nosh)

{

    point* pNosh;

     pNosh=new point;

     pNosh->c=nosh;

     pNosh->next=NULL;

     return 0;

}

这样的话,又得添加一个公共函数了,这个函数就用来负责管理输入的字符,由他决定输入的字符应该怎么处理。

三、既然这样,干脆,我们再添几个私有函数,负责下面的几项任务:

1、   产生一个新的line;(正好,在产生新的line的时候我们可以让他先去判断一下前面的line的最后是不是空格,如果是的话,先删除掉)

2、   (暂时还没想到,呵呵)

int CTxtMonster::NewLine()

{

     if (txt_tree.head->head==NULL)            //别担心txt_tree.head是一个NULL,

return 1;                              //因为在构造时就添了一个line

                                               //先将当前line的末尾的空格去掉

     while(txt_tree.head->head->c==32)        //注意:这个删除空格的过程并没有检查

//是否会全部删除,在调用这个函数前要自行判断

     {

         point* t=NULL;

          t=txt_tree.head->head->next;

         delete txt_tree.head->head;

          txt_tree.head->head=t;

     }

     line* newline=NULL;

     newline=new line;

     newline->head=NULL;

     newline->next=NULL;

     newline->next=txt_tree.head;

     txt_tree.head=newline;

}      

四、下面来看看构造和析构函数

构造函数还是比较方便的:

CTxtMonster::CTxtMonster()

{

               txt_tree.head=NULL;

               line* first_line=NULL;

               first_line->head=NULL;

               first_line->next=NULL;

               txt_tree.head=first_line;

          }

     析构函数就比较麻烦了,她要遍历整个结构,看样子,还要添一个删除line的内部函数

—int DelLinePoint(line*)这个函数只是删除pkill所指的line下的所有的point

     CTxtMonster::~CTxtMonster()

{

     /**********************

      释放所有单元

     **********************/

 

     Killme(txt_tree.head);

}

 

int CTxtMonster::Killme(line* pkill)

{

     if(pkill->next!=NULL)

          Killme(pkill->next);

     DelLinePoint(pkill);

     delete pkill;

     return 0;

}

 

int CTxtMonster::DelLinePoint(line* pkill)

//这个函数只是删除pkill所指的line下的所有的point

{

     while(pkill->head!=NULL)

     {

         point* t=NULL;

          t=pkill->head;

          pkill=t->next;

         delete t;

     }

     return 0;

}

////////////////以上三个函数完成了对所有空间的收回。

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐