提倡同学们积累代码行数,于是有了大量的编程练习。做下来是一个基本的要求,对个别同学而言,已经是轻松面对,他们在基本编程能力方面,已经有了保障,这为今后的学习和自学打下了好的基础。一些同学一路紧随,跟住了都不是易事,有些依然不能按时按量完成。心中想着要多做几个,但调试中遇到问题,难免急躁。
  看到一位同学在博文最后写的一段话:“直接抓狂了,经过个人分析,应该是函数change24与changefrom0没有实现其功能,可是定义函数,函数的赋值及调用都与其他同学的相同,问题究竟出在哪里啊?求指点!”
  这是C++第7周项目1 - 静态成员应用于时间类(见 http://blog.csdn/sxhelijian/article/details/8795951) 的题目。目标是学会静态数据成员以及静态成员函数的用法。
  下面是只涉及静态数据成员以及静态成员函数的用法的“缩略版”解答,当然,包含这位同学犯的错误。请读者先读完这段程序。
#include <iostream>
#include<string>
using namespace std;
class Time
{
public:
    Time(int=0,int=0,int=0);
    void show_time( ); //根据is_24和from0,输出适合形式-20:23:5/8:23:5 pm/08:23:05 pm
    static void change24();  //改变静态成员is_24,在12和24时制之间转换
    static void changefrom0();   //改变静态成员from0,切换是否前导0
private:
    static bool is_24; //为true时,24小时制,如20:23:5;为flase,12小时制,显示为8:23:5 pm
    static bool from0; //为true时,前导0,8:23:5显示为08:23:05
    int hour;
    int minute;
    int sec;
};
Time::Time(int h,int m,int s)
{
    hour=h;
    minute=m;
    sec=s;
}
bool Time::is_24=true;
bool Time::from0=false;
void Time::show_time( )
{
    int h=(is_24)?hour:hour%12;
    if (h<10&&from0) cout<<'0';
    cout<<h<<':';
    if(minute<10&&from0) cout<<'0';
    cout<<minute<<':';
    if(sec<10&&from0) cout<<'0';
    cout<<sec;
    if(!is_24)
        cout<<((hour>12)? " pm":" am");
    cout<<endl;
}
void Time::change24()
{
    is_24=!is_24;
}
void Time::changefrom0()
{
    from0=!from0;
}
int main( )
{
    Time t1(23,14,25),t2(8,45,6);
    cout<<"24小时制,不导0:"<<endl;
    t1.show_time();
    t2.show_time();


    cout<<"切换是否前导0:"<<endl;
    t1.changefrom0();
    t2.changefrom0();
    t1.show_time();
    t2.show_time();


    cout<<"换一种制式:"<<endl;
    t1.change24();
    t2.change24();
    t1.show_time();
    t2.show_time();
}

  这段程序的实际运行结果是:
  
  可以发现,切换是否前导0,换制式,根本没有起作用。预期中的结果应该是:
  
  面对运行中的问题,最直接的办法就是采用单步执行的办法,跟踪一下程序在执行过程中,相关变量的变化过程。显然,这位同学并没有这样做过。
  一再强调的调程序的“利器”,就被藏在“兵器库”中,任由其闲置。这种技能就是要在实践中学会的,这是学会的最佳时刻。有些同学已经用得纯熟,有些还在躲避。同一个教室上课,差别怎么这么大。
  不说这些了。其实,不用单步调试,这个事不好做,也真不好说。初学有关知识,都要靠着推理式的排查,这是更难的办法。
  这个程序中包括main()函数在内一共5个函数。类的构造函数Time()和用于显示的函数Time::show_time()嫌疑不大,先放过。main()似乎中规中矩,也放下。Time::changefrom0()和Time::change24()与以前编程的程序中有点不一样,声明前加了个static,这时可以看书了,明确这叫做静态成员函数,静态成员函数是用来使用静态数据成员的,再看static bool is_24; 和static bool from0; ,这两个成员不一般,静态的,静态的有何特点?它不属于任何一个对象,属于类。然后看看讲义,老师讲过这个图:
  
  围绕着“静态”,找到main()函数中有这么两句,调用的是静态成员函数:
    t1.changefrom0();
    t2.changefrom0();
  这两个静态成员函数操作的将是同一个数据Time::from0,尽管t1.changefrom0()和t2.changefrom0()前面打着t1、t2人民的旗号,干得都是服务大众的工作。from0和hour等不一样,它是静态的。
  于是明白了吧。t1.changefrom0()将from0由假为真,t2.changefrom0()又将from0由真为假,最后输出没有变化。

  发生在is_24上的事情也是一样。

  程序运行结果不在预期中,这是学习的最佳机会。

  稀里糊涂走进来,明明白白走出去。这大概是积累代码行的路线中应该收获的,而其中需要的,是冷静,以及实践与看书的结合。

  最后,还说,单步调试,闲着太可惜。



更多推荐

编程学习,从意外中收获