Tour

Action speaks louder than words ...

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

  之前工作中遇到一个问题,就像题目中描述的那样,看起来题目有些拗口复杂,这里解释下,当时遇到的需求需要这样处理:调用某个类对象的某个成员函数时,第一次有具体意义的,其他时候都是保持不变的、无意义的。这个需求可以看做是在调用某成员函数时,第一次进行初始化,其他时候不进行操作,即在首次调用时进行初始化,根据这点,很容易想到c/c++里面的static变量,它的作用是保持变量内容的持久,存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。根据需求,使用static局部变量,写下如下代码:

 1 class T
 2 {
 3 public:
 4     T(const char * pstr):value(pstr){}
 5     void Print()const;
 6 private:
 7     string value;
 8 };
 9 
10 void T::Print()const
11 {
12     static bool bFirstCall = true;
13     if(bFirstCall)
14     {
15         cout<<"first Call "<<value<<endl;
16         bFirstCall = false;
17     }
18     else
19     {
20         cout<<"not first Call "<<value<<endl;
21     }
22 }

即在类的成员函数中定义一个局部的静态变量,使得第一次调用进行初始化,用以区分是否是第一次调用,之后运行else分支。运行下面的测试代码,输出结果见下图:

 1 int _tmain(int argc, _TCHAR* argv[])
 2 {
 3     T t1("Grubby");
 4     t1.Print();
 5     t1.Print();
 6 
 7     T t2("Moon");
 8     t2.Print();
 9     t2.Print();
10 
11     return 0;
12 }

通过输出可以看到,t1得到了想要的结果,但是两次t2.Print()都打印 "not first Moon",这说明此时 bFirstCall 还是false。于是在Print函数中打印bFirstCall地址的代码:

 1 void T::Print()const
 2 {
 3     static bool bFirstCall = true;
 4     printf("addr of bFirstCall is %x\n", &bFirstCall);
 5     if(bFirstCall)
 6     {
 7         cout<<"first Call "<<value<<endl;
 8         bFirstCall = false;
 9     }
10     else
11     {
12         cout<<"not first Call "<<value<<endl;
13     }
14 }

再次运行输出如下:

看到四次调用Print函数时打印的bFirstCall的地址相同,这说明类成员函数中的局部静态变量同样属于此函数,而不属于某个对象,不会因为重新定义一个t2对象,第一次调用 t2.Print()时 bFristCall 是 true,不管是哪个T类对象,只在第一次调用 Print()时,bFirstCall == ture。于是无奈对程序进行了修改,将bFristCall定义为类的静态成员,每次构造函数是将其重置为true:

 1 class T
 2 {
 3 public:
 4     T(const char * pstr):value(pstr){ bFirstCall = true;}
 5     void Print()const;
 6 private:
 7     string value;
 8     static bool bFirstCall;
 9 };
10 bool T::bFirstCall;
11  
12 void T::Print()const
13 {
14     if(bFirstCall)
15     {
16         cout<<"first Call "<<value<<endl;
17         bFirstCall = false;
18     }
19     else
20     {
21         cout<<"not first Call "<<value<<endl;
22     }
23 }

运行测试代码可以得到想要的结果:

但是这里又出现了新的问题,即每次构造函数是将bFirstCall重置为true时,如果新定义一个对象,并且没有调用Print()函数,那么再次调用之前定义对象的Print()函数,会产生与预期相反的结果,考虑如下测试代码:

 1 int _tmain(int argc, _TCHAR* argv[])
 2 {
 3     T t1("Grubby");
 4     t1.Print();
 5     t1.Print();
 6 
 7     T t2("Moon");
 8     t1.Print();
 9 
10     return 0;
11 }

运行输出如下:

避免这种情况,目前只能保证顺序的对每个对象进行类似Print这样函数的初始化调用,还没有想到好的解决办法。

posted on 2014-11-06 23:24  Tourun  阅读(2415)  评论(3编辑  收藏  举报