201605程序员下午真题

第 1 题

 阅读以下说明和流程图,填补流程图和问题中的空缺(1)~(5),将解答填入答题纸的对应栏内。
【说明】
设整型数组A[1:N]每个元素的值都是1到N之间的正整数。一般来说,其中会有一些元素的值是重复的,也有些数未出现在数组中。下面流程图的功能是查缺查重,即找出A[1:N]中所有缺的或重复的整数,并计算其出现的次数(出现次数为0时表示缺)。流程图中采用的算法思想是将数组A的下标与值看作是整数集[1:N]加上的一个映射,并用数组C[1:N]记录各整数出现的次数,需输出所有缺少的或重复的数及其出现的次数。

【流程图】



【问题】
  如果数组A[1:5]的元素分别为{3,2,5,5,1},则算法流程结束后输出结果为: (5) 
  输出格式为:缺少或重复的元素,次数(0表示缺少) **答案与解析** - 试题难度:较难 - 知识点:流程图>流程图 - 试题答案:

(1)A[i]
(2)C[k]+1
(3)1
(4)k 和C[k]
(5) 4,0
5,2

- 试题解析:

(1)A[i] //A[i]赋给K,
(2)C[k]+1//C[k]值加1,i循环中,将A{i}中存在的值在C[k]中相应位数上加1。以A[1:5]={3,2,5,5,1}为例,当i=1时,k=A[1]=3,则C[3]+1,即C[1:5]变成{0,0,1,0,0}。当i=2时,k=A[2]=2,则C[2]+1,即C[1:5]变成{0,1,1,0,0}。当i循环结束后,C[k]={1,1,1,0,2}.
(3)1 //判断C[k]值是否为1,是1的时候不输出,不是1的时候共有两种情况:0/>1,为零这说明缺少k值,为>1时,说明K重复出现,出现次数为k次。
(4)k 和C[k] //k位重复数,C[k]为重复次数
(5)在范例中,4没有出现,1、2、3分别出现了1次,5出现了两次。

### 第 2 题  阅读以下说明和C代码,填补代码中的空缺,将解答填入答题纸的对应栏内。 【说明1】
    递归函数is_elem(char ch, char *set)的功能是判断ch中的字符是否在set表示的字符集合中,若是,则返回1,否则返回0。
【C代码1】
int is_elem (char ch ,char*set)
{
     if(*set==‘\0’)
         return 0;
    else
       if(     (1)     )
         return 1;
      else
        return is_elem(   (2)    )
}
 
【说明2】
函数char*combine(char* setA,char *setB)的功能是将字符集合A(元素互异,由setA表示)和字符集合B(元素互异,由setB表示)合并,并返回合并后的字符集合。
【C代码2】
 char*combine(char *setA, char*setB)
 {
    int i,lenA, lenB, lenC;
    lenA=strlen(setA);
    lenB=strlen(setB);
    char*setC=(char*)malloc(lenA+lenB+1);
    if(!setC)
        return NULL;
    strncpy(setC,setA,lenA);       //将setA的前lenA个字符复制后存入setC
    lenC=      (3)     ;
    for(i=0;i<lenB;i++)
         if(    (4)    )             //调用is_elem判断字符是否在setA中
               setC[lenC++]=setB[i];
        (5)    =‘/0’;        //设置合并后字符集的结尾标识
    return setC;
} **答案与解析** - 试题难度:较难 - 知识点:C程序设计>C程序设计 - 试题答案:(1)set[0]==ch
(2)ch,set+1
(3)lenA
(4)is_elem(setB[i],setA)==0
(5)setC[lenC] - 试题解析: 1. If(set[0]==ch)  //取出set第一个元素与ch字符比较是否相等,若相等,则返回为1,标明字符集合中包含该字符串。
 2. return is_elem(ch,set+1) // 从set第二个元素开始重新递归代入函数执行,以此类推,直到结束或者到达串尾。这里采用了递归调用的方式。
在这里,函数char*combine(char* setA,char *setB)的功能是将字符集合A(元素互异,由setA表示)和字符集合B(元素互异,由setB表示)合并,并返回合并后的字符集合。处理思路是:先将集合A里面的字符串全部赋给集合C,然后再让集合B里面的每个字符与集合A进行is_elem函数运算,判断集合B里面的每个字符是否在集合A中出现过,如果在,则忽略,如果不在,则需要将这一元素加入到字符C中。
 3. strncpy(setC,setA,lenA);       //将setA的前lenA个字符复制后存入setC
     lenC=lenA; 变量lenC表示setC的字符个数,其初始值应为lenA。
for(i=0;i<lenB;i++)
  if is_elem(setB[i],setA)==0)        //调用is_elem判断字符是否在setA中,若存在,则忽略,若不存在,则在setC字符集合里新增SetB[i].
setC[lenC++]=setB[i];
setC[lenC]=‘/0’;      //设置合并后字符集的结尾标识,lenC 自动跟踪了该元素数目的变化,其最后的值正好等于setC元素个数。
returnsetC; ### 第 3 题   阅读以下说明和C代码,填补代码中的空缺,将解答填入答题纸的对应栏内。 【说明】
    某文本文件中保存了若干个日期数据,格式如下(年/月/日):
    2005/12/1
    2013/2/29
    1997/10/11
    1980/5/15
     ....
    但是其中有些日期是非法的,例如2013/2/29是非法日期,闰年(即能被400整除或者能被4整除而不能被100整除的年份)的2月份有29天,2013年不是闰年。现要求将其中自1985/1/1开始、至2010/12/31结束的合法日期挑选出来并输出。
    下面的C代码用于完成上述要求。
 
【C代码】
#include <stdio.h>
typedef struct{
    int year, month, day;/* 年,月,日*/
}DATE;
 
int isLeap Year(int y)       /*判断y表示的年份是否为闰年,是则返回1,否则返回0*/
{
      return((y%4==0 && y%100!=0)Il(y%400==0));  
}   
  
int isLegal(DATE date)   /*判断date表示的日期是否合法,是则返回1,否则返回0*/
{
int y=date.year,m= date.month,d=date.day;
 
if (y<1985 II y>2010 II m<1 II m>12 II d<l II d>31)   return 0;
    if((m==4 ll m==6 ll m==9 II m==11)&&    (1)    )  return 0;
If(m==2){
       if(isLeap Year(y)&&    (2)   )  return 1;    。
       else
          if (d>28) return 0;
    }
return 1;
}
 
 
Int Lteq(DATE d1,DATE d2)
/*比较日期d1和d2,若d1在d2之前或相同则返回1,否则返回0*/
{
      Long t1,t2;
      t1=d1.year*10000+d1.month*100+d1.day;
      t2=d2.year*10000+d2.month*100+d2.day;
      if(    (3)    )     return 1;
      else          return 0;
}
 
int main()
{
     DATE date,start={1985,1,1},end={2010,12,30};
     FILE*fp;
 
     fp=fopen(“d.txt”,”r”);
     If(     (4)    )
           return-1;
 
     while(!feof(fp)){
         if(fscanf(fp,”%d%d%d”,&date.year,&date.month,&date.day)!=3)
             break;
         if(   (5)   )        /*判断是否为非法日期 */
             continue;
         if(   (6)   )       /*调用Lteq判断是否在起至日期之间*/
             printf(“%d%d%d\n”,date.year,date.month,date.day);
  }
        fclose(fp);
 
        Return 0;
} **答案与解析** - 试题难度:较难 - 知识点:C程序设计>C程序设计 - 试题答案:(1)d>30 /d==31或其等价表示
(2)d<=29或其等价表示
(3)t1<=t2/t1-t2<=0或其等价表示
(4)fp==null/!fp或其等价表示
(5)!isLegal(date) 或其等价表示
(6)Lteq(start,date)==1&&Lteq(date,end)==1 / Lteq(start,date)&&Lteq(date,end) 或其等价表示 - 试题解析:(1)(2)理解:
if((m==4 ll m==6 llm==9 II m==11)&&   d>30 /d==31)  return 0;   //如果月份是4,6,9,11并且天数等于31则返回不合法,这几个月最多为30天,不可能等于31。
If(m==2){
       if(isLeap Year(y)&&  d<=29  )  return 1;
else
          if (d>28) return 0;//当年份为闰年的时候,那么二月份的天数需小于或等于29。合法则返回1。

(3)if(    t1<=t2/t1-t2<=0   )     return 1;    //d1在d2之前,那么表明日期经换算成t1、t2后,t1<=t2。
(4)If(  fp==null/!fp  )//先要判断文件是否为空;
(5)(6)理解: 
     isLegal(date)判断date表示的日期是否合法,是则返回1,否则返回0,此处非法日期不输出,故:
             if(    !isLegal(date)     )        /*判断是否为非法日期 */  
            continue;
       if(Lteq(start,date)==1&&Lteq(date,end)==1 ) /*调用Lteq判断是否在起至日期之间,Lteq(t1,t2)的含义是比较日期d1和d2,若d1在d2之前或相同则返回1,否则返回0。*/ ### 第 4 题 阅读以下说明和C代码,填补代码中的空缺,将解答填入答题纸的对应栏内。
【说明】
    二叉查找树又称为二叉排序树,它或者是一棵空树,或者是具有如下性质的二叉树。
(1)若它的左子树非空,则左子树上所有结点的值均小于根结点的值。
(2)若它的右子树非空,则右子树上所有结点的值均大于根结点的值。
(3)左、右子树本身就是两棵二叉查找树。
    二叉查找树是通过依次输入数据元素并把它们插入到二叉树的适当位置上构造起来的,具体的过程是:每读入一个元素,建立一个新结点,若二叉查找树非空,则将新结点的值与根结点的值相比较,如果小于根结点的值,则插入到左子树中,否则插入到右子树中;若二叉查找树为空,则新结点作为二叉查找树的根结点。
    根据关键码序列{46,25,54,13,29,91}构造一个二叉查找树的过程如图4-1所示。
设二叉查找树采用二叉链表存储,结点类型定义如下:
typedef int KeyType;
typedef  struct  BSTNode{
    KeyType key;
    struct  BSTNode  *left,*right;
}BSTNode,*BSTree;
 
图4-1(g)所示二叉查找树的二叉链表表示如图4-2所示。

图4-2
函数int InsertBST(BSTree *rootptr,KeyType kword)功能是将关键码kword插入到由rootptr指示出根结点的二叉查找树中,若插入成功,函数返回1,否则返回0。 【C代码】
int lnsertBST(BSTree*rootptr,KeyType kword)
/*在二叉查找树中插入一个键值为kword的结点,若插入成功返回1,否则返回0;
  *rootptr为二叉查找树根结点的指针
*/
{
   BSTree p,father;
 
        (1)     ;                    /*将father初始化为空指针*/
   p=*rootptr;                       /*p指向二叉查找树的根节点*/
   while(p&&   2  ){           /*在二叉查找树中查找键值kword的结点*/
       father=p;
       if(kword<p->key)
           p=p->left;
       else
           p=p->right;
}
if(   (3)    )    return 0;              /*二叉查找树中已包含键值kword,插入失败*/
 
p=(BSTree)malloc(    (4)    );       /*创建新结点用来保存键值kword*/
If(!p)return 0;                       /*创建新结点失败*/
p->key=kword;
p->left=NULL;
p->right=NULL;
 
If(!father)
           (5)    =p;     /*二叉查找树为空树时新结点作为树根插入*/
else
     if(kword<father->key)
          (6)      ;     /*作为左孩子结点插入*/
else
          (7)       ;      /*作右孩子结点插入*/
 
   return 1;
 
}/*InsertBST*/ **答案与解析** - 试题难度:较难 - 知识点:C程序设计>C程序设计 - 试题答案:1)father=0/father=NULL
2)keyword!=p->key
3)p
4)sizeof(BSTNode)
5)*rootptr
6)father->left=p
7)father->right=p 
- 试题解析:本题考查C程序设计的基本结构和数据结构的实现。
根据二叉查找树的定义,其左子树中结点的关键码均小于树根结点的关键码,其右子树中结点的关键码均大于根结点的关键码,因此,将一个新关键码插入二叉查找树时,若等于树根或某结点的关键码,则不再插入,若小于树根,则将其插入左子树中,否则将其插入右子树中。
根据注释,空(1)处需将father设置为空指针,应填入“father=NULL”或其等价形式。
空(2)所在语句用于查找新关键码的插入位置,p指向当前结点。查找结果为两种:若找到,则p指向的结点的关键码等于新关键码,若没有找到,则p得打空指针值。因此空(2)处应填入“p->key!=kword”或其等价形式,在得到结果前使得查找过程可以继续,并且用father记录新插入结点的父结点指针。
空(3)处应填入“p”或其等价形式,表明查找到了kword相同的结点,无须在插入该关键码。
空(4)处应填入“sizeof(BSTNODE)”,在申请新结点空间时提供结点所需的字节数。
空(5)处应填入“*rootptr”,使得新结点作为树根结点时,树根结点的指针作为二叉链表的标识能得到更新。
根据注释,空(6)应填入“father->left=p”、空(7)应填入“father->right=p”。 ### 第 5 题   阅读以下说明和Java代码,填补代码中的空缺,将解答填入答题纸的对应栏内。
【说明】  
以下Java代码实现两类交通工具(Flight和Train)的简单订票处理, 类Vehicle、Flight、Train之间的关系如图5-1所示。
图5-1

【Java代码】
import java.util.ArrayList;
import java.util.List;
 
abstract class Vehicle {
     void book(int n) {                    //订 n张票
          if (getTicket0()>=n) {
           decrease Ticket(n);
         } else {
             System.out.println(“余票不足!!“);          
         }
     }
     abstract int getTicket();
     abstract void decreaseTicket(int n);
};
 
class Flight  (1) {
     Private (2) tickets=216;    //Flight的票数
     Int getTicket(){
               Return tickets;
     }
     void decreaseTicket(int n){
          tickets=tickets -n;
     }
}
 
class Train (3) {
     Private (4) tickets=2016;        //Train的票数
     int getTicket() {
        return tickets;
     }
     void decreaseticket(int n) {
           tickets = tickets - n;
    }
}
 
public class Test
{
    public static void main(String[] args) {
  
          System.out.println(“欢迎订票 ! ");
          ArrayList<Vehicle> v = new ArrayList<Vehicle>();
          v.add(new Flight());
          v.add(new Train());
          v.add(new Flight());
          v.add(new Train());
          v.add(new Train());
 
           for (int i=0;i<v.size(); i++){
                 (5)  (i+1);   //订i+1张票
          System.out.println(“剩余票数:” +v.get(i).getTicket());
          }
    }
}
 
运行该程序时输出如下:
欢迎订票!
剩余票数:215
剩余票数:2014
剩余票数:  (6) 
剩余票数:  (7) 
剩余票数:  (8) 

答案与解析

  • 试题难度:较难
  • 知识点:Java程序设计>Java程序设计案例
  • 试题答案:(1)extends Vehicle    
    (2)static  int     
    (3)extends Vehicle     
    (4)static  int
    (5)v.get(i).book        
    (6)212              
    (7)2010                     
    (8)2005
  • 试题解析:本题考查Java语言程序设计,涉及类、继承、对象、方法的定义和相关操作。要求考生根据给出的案例和代码说明,认真阅读理清程序思路,然后完成题目。
    先考查题目说明,实现两类交通工具(Flight和 Train)的简单订票处理,根据说明进行设计。题目说明中图5-1的类图给出了类Vehicle、Flight、Train之间的关系。设计到交通工具类Vehicle、其子类Flight和Train两类具体交通工具。简单订票就针对这两类具体的交通工具,每次订票根据所选订票的交通工具和所需订票数进行操作。
    不论哪种交通工具,订票操作book在余票满足条件的情况下会将余票减少所定票数,不足时则给出“余票不足”提示,所以在父类Vehicle中定义并实现 void book(int n)方法。每类具体交通工具获取自身类型的票数(getTicket),订票也只减少自身类型票数(decreaseTicket(int n))等类以及相关操作。因此,在父类Vehicle中,分别定义针对上述两个操作的抽象方法:
     
    abstract int getTicket();
    abstract void decreaseTicket(int n);
     
    在Java中,abstract作为抽象方法的关键字,包含抽象方法的类本身也必须是抽象类,因此,类Vehicle前需要有abstract关键字修饰,即:
     
     Abstract class Vehicle{ ……}
     
    而且,抽象方法必须由其子类实现。从题目说明中给出的类图(图5-1)也可以看出,Vehicle的两种具体类(子类)为Flight和Train。在Java中,子类集成父类用关键字extends,不论父类是抽象类还是具体类,即:
    Class 子类名 extends 父类名
    因此,Flight和Train的定义分别为:
    Class Flight extends Vehicle
    Class Train extends Vehicle
    Flight类和Train类中必须实现getTicket和decreaseTicket方法才能进行获取票数和减少余票的操作。因此,这两个类中都实现getTicket和decreaseTicket方法
    Flight和Train两类具体交通工具的票数需要分别记录,并且每次订票操作需要对总数进行操作,所以定义为变量,同一类的所有对象共享此变量。在Java中,定义类变量的方式是将变量定义为静态变量,即用static关键字修饰。同时分析票数的使用,getTicket和decreaseTicket两个方法的返回值和参数类型都用int,因此,票数tickets也定义为int。综合上述两个方面知,tickets定义为static int类型
    测试类Test中实现了订票系统的简要控制逻辑,主控制逻辑代码实现在main()方法中,其中创建欲进行订票的对象、持有对象的集合、订票逻辑等。定义ArrayList<Vehicle>链表集合类型变量V,此处采用泛型集合,在V中,可以持有Vehicle类型及其子类型的对象。ArrayList<E>链表集合中的方法add(E e)用于给链表集合的最末端添加元素,get(int index)用以获取链表集合中索引位置为index的元素,size()用以获取链表集合中的元素个数。主控逻辑中创建Flight和Train两个具体类的一些订票请求对象加入V中,因为Flight和Train均为vehicle的子类型,而已是具体类,所以满足加入元素的要求,故采用new Flight和new Train()来创建相应的对象加入V中:然后通过for循环使每个订票请求进行订票,并输出剩余票数:
    For(in ti=0;i<v.size();i++){
               V.get(i).book(i+1);    //订i+1张票
               System.out.println(“剩余票数:”+v.get(i).getTicket() );
               }
    即从v中取每个对象,调用book方法进行订票操作。V.get(i)获取v中位置为i的元素,即Vehicle类型的对象,Java中,动态绑定机制使得不同对象接受同一消息后发生不同的响应,即具体行为由位置为i的对象决定。此处无须类型转化,这是因为在父类Vehicle中,已经定义了book方法,并且申明了book所调用的getTicket和decreaseTicket方法接口,子类分别加以实现。另外,在上述getTicket和decreaseTicket两个方法执行时,因为每次操作tickets为static静态类型,所以,每个操作都是上次对象修改之后的值的基础上继续更新。
    在main()方法中,依次新建并加入了5个对象,按顺序类型分别为:Flight、Train、Flight、Train、Train,加入v中的index分别为0、1、2、3、4。在for循环中,按顺序获取。链表集合中的对象元素,并进行订票,数量为i+1张,然后输出剩余票数。因此,采用v.get(i).book(i+1)进行订票,采用v.get(i).getTicket()获得当前对象元素所属类的剩余票数。其中Flight的剩余票数216-1=215、215-3=212;Train的剩余票数为2016-2=2014、2014-4=2010、2010-5=2005。
    综上所述,空(1)和(3)需要表示继承Vehicle抽象类,即extends Vehicle;空(2)和(4)需要分别表示Flight和Train中tickets变量为静态整形变量。即static int;空(5)处为调用获取V中对象元素并订票的v.get(i).book;空(6)为212;空(7)为2010;空(8)为2005。

第 6 题

  阅读下列说明和C++代码,填补代码中的空缺,将解答填入答题纸的对应栏内。
【说明】
    以下C++代码实现两类交通工具(Flight和Train)的简单订票处理,类Vehicle、Flight、Train之间的关系如图6-1所示。

   图6-1

【C++代码】

include <iostream>

include <vector>

using namespace std;
 
class Vehicle{
public:
    virtual ~Vehicle(){}
    void book(int n){    //订n张票
       if (getTicket()>=n){
           decreaseTicket(n);
        } else{
            cout<<n<<“余票不足!!  ”;
      }
    }
    virtual int getTicket()=0;
    virtual void decreaseTicket(int)=0;
};
Class Flight:   (1)   {
private:
          (2)  tickets;      //Flight的票数
public:
       int getTicket();
       void decreaseTicket(int);
};
class Train:   (3)   {
private:
        (4)  tickets;     //Train的票数
public:
     int getTicket();
     void decreaseTicket(int);
};
int Train::tickets =2016;       //初始化Train的票数为2016
int Flight::tickets =216;      //初始化Flight的票数为216
 
int Train::getTicket()  {  return tickets; }
void Train::decreaseTicket(int n){  tickets=tickets -n;}
 
int Flight::getTicket ()     {    return tickets;    }
void Flight::decreaseTicket(int n) {    tickets= tickets - n;}
 
int main() {
vector<Vehicle> v;
 
   v.push_back(new Flight());
   v.push_back(new Train());
   v;push_back(new Flight());
   v.push_back(new Tram());
   v.push_back(new Train());
 
    cout《"欢迎订票!”《endl:
    for (int i= 0; i < v.size(); i++) {
             (5)  (i+1);  //订i+1张票
             cout《“剩余票数:”<<(
V[i]). getTicket()<<endl;
}

for (vector<Vehicle>::iterator it = v.begin(); it != v.end(); it ++)  {
      if (NULL !=
it) {
         deleteit ;
         
it = NULL;
           }
   }
   v.clear();
   return0;
}
运行该程序时输出如下:
欢迎订票!
剩余票数:215
剩余票数:2014
剩余票数:  (6)
剩余票数:  (7) 
剩余票数:  (8)        

答案与解析

  • 试题难度:较难
  • 知识点:C++程序设计>C++程序设计
  • 试题答案:(1)public Vehicle
    (2)static  int
    (3)public Vehicle
    (4)static  int
    (5)(*v[i]).book
    (6)212
    (7)2010
    (8)2005
  • 试题解析:本题考查C++语言程序设计,涉及类、继承、对象、函数的定义和相关操作。要求考生根据给出的案例和代码说明,认真阅读理清程序思路,然后完成题目。
    先考查题目说明,实现两类交通工具(Flight和Train)的简单订票处理,根据说明进行设计,题目说明中图6-1的类图给出了类Vehicle、Flight、 Train之间的关系。涉及到交通工具类Vehicle、其子类Flight和Train两类交通工具。简单订票就是针对这两类具体的交通工具,每次订票根据所选订票的交通工具和所需订票数进行操作。
    不论哪类交通工具,订票操作book在余票满足条件的情况下将余票减少所定票数,不足时则给出“余票不足”的提示,所在父类Vehicle中定义并实现void book(int n)函数。
    每类具体交通工具获取自身类型的票数(getTicket),订票也只减少自身类型票数(decreaseTicket(int n))等类以及相关操作。因此,在父类Vehicle中,分别定义针对上述两个操作的虚函数:
    Virtual int getTicket() =0;
    Virtual void decreaseTicket(int n)=0;
    在C++中,virtual作为虚函数的关键字,“=0;”表示为纯虚函数,包含虚函数的类本身也是虚拟类,而且,虚函数必须由其子类实现。从题目说明给出的类图(图6-1)也可以看出,Vehicle的两种具体类(子类)为Flight和Train。在C++中,子类继承父类“:”,即:
    Class 子类名:继承的方式 父类名
    考查主控函数main(),需要将Flight和Train类型对象加入模板类型为Vehicle的向量中,因为Flight和Train的实现分别为:
    Class Flight : public Vehicle
    Class Train  : public Vehicle
    Flight和Train类中必须实现getTicket和decreaseTicket函数才能进行获取票数和减少余票的操作。因此,在两个类别中都实现了getTicket和decreaseTicket函数
    Flight和Train两类具体交通工具的票数需要分别记录,并且每次订票操作需要对总数进行操作,所有需要定义为类变量,同一类的所有对象共享此变量。在C++中,定义类变量的方式是将变量定义为静态变量,即用static关键字修饰。同时分析对票数的使用,getTicket和decreaseTicket两个函数的返回值和参数都用类型int,因此,票数tickets也定义为int。综合上述两个方面知,tickets定义为static int类型。而且在C++中static int类型的变量必须在类外进行初始化,即:
    int Train: :tickets=2016;            //初始化Train的票数为2016
    int Flight: :tickets=2016;          //初始化Flight的票数为2016
    主函数main()实现了订票系统的简要控制逻辑,其中创建欲进行订票的对象、持有对象的集合、订票逻辑等。定义vector<Vehicle>向量类型变量v,此处采用模板类集合,在v中,可以持有Vehicle类型及其子类的对象指针。Vector<E>向量中的函数push_back(E e)用于给向量的最末端添加元素,采用向量元素下边index获取向量中索引位置为index的元素,即对象指针,size()用以获取向量的元素个数。主控逻辑中创建Flight和Train两个具体类的一些订票请求对象加入v中,因为Flight和Train均为Vehicle的子类型,而且是具体类,所以满足加入元素的要求,故采用new Flight()和 new Train()来创建相应的对象加入V中;然后通过for循环使每个订票请求对象进行订票,并输出剩余票数:
       for(in ti=0;i<v.size();i++){
           (v[i]).book(i+1);   //订i+1张票
           Count<<“s剩余票数:”<<(
    v[i].getTicket()<<endl;
           }
    即从v中取每个对象指针,用其指针的对象调用book函数进行订票操作。V[i]获得v中位置为i的元素,(V[i])则是Vehicle类型的对象,由于面向对象的多态机制使得不同对象接受同一消息后发生不同的响应,即具体行为由位置为i的对象指针所引用的对象决定。此处无须类型转换,这是因为在父类Vehicle中,已经定义了book函数,并且声明了book所调用的getTicket和decreaseTicket函数接口,子类分别加以实现。另外,在上述getTicket和decreaseTicket两个函数执行时,因为每次操作tickets和static静态类型,所以,每个操作均作用在当前类变量的剩余票数,即具体子类的有唯一一个当前剩余票数,每次操作都是上次对象修改之后的值的基础上继续更新。
    在main()函数中,依次新建并加入5个对象,按顺序类型分别为:Flight、Train、Flight、Train、Train,加入v中的index分别为0、1、2、3、4.在for循环中,按顺序获取向量中的对象元素,并进行订票,数量为i+1张,然后输出剩余票数。因此,采用(
    v[i]).book(i+1)进行订票,采用(v[i]).getTicket()获得当前对象元素所属类的剩余票数。其中Flight的剩余票数216-1=215、215-3=212;Train的剩余票数为2016-2=2014、2014-4=2010、2010-5=2005.按对象顺序则为:215、2014、212、2010、2005。
    综上所述,空(1)和(3)需要表示基础Vehicle虚类,即public Vehicle;空(2)和(4)需要分别表示Flight和Train中tickets变量为静态整形变量,即static int;空(5)处为调用获取v中对象元素并订票的(
    v[i]).book;空(6)为212;空(7)为2010;空(8)为2005。

results matching ""

    No results matching ""