东软2012-11月笔试题
- <SPAN style="FONT-SIZE: 14px">class Sample
- {
- int x;
- public:
- Sample(int a)
- {
- x = a;
- cout << "constructing object: x =" << x << endl;
- }
- };
- void func(int n)
- {
- static Sample obj(n);
- }
- int main()
- {
- func(1);
- func(10); //1
- return 0;
- }
- </SPAN>
[分析]:题目的考查点,静态对象的创建及执行。类中的静态对象只会执行一次,这是输出上面结果的原因。
[扩展分析]:此种静态对象的题目之前在360面试的时候被问到过,后来在《深入浅出MFC》基础部分讲解C++重要性质之——C++程序的生与死:兼谈构造函数与析构函数部分的示例很能说明问题。
笔者对示例稍稍做了扩充,如下:
- <SPAN style="FONT-SIZE: 14px"> class CDemo
- {
- public:
- CDemo(const char* str);
- ~CDemo();
- void showObjectName(); //显示对象名。
- private:
- char name[20];
- };
- CDemo::CDemo(const char* str)
- {
- strncpy_s(name,str,20);
- cout << "Constructor called for " << name << "\n";
- }
- CDemo::~CDemo()
- {
- cout << "Destructor called for " << name << "\n";
- };
- void func()
- {
- CDemo LocalObjectInFunc("LocalObjectInFunc"); //5 //10
- static CDemo staticObject("StaticObject"); //6
- CDemo* pHeapObjectInFunc = new CDemo("HeapObjectInFunc"); //7 //11
- cout << "Inside func" << endl; //8 //12
- } //9析构LocalObjectInFunc //13析构LocalObjectInFunc
- void CDemo::showObjectName() //显示对象名
- {
- cout << name << "\n";
- }
- CDemo GlobalObject("GlobalObject"); //1
- int main()
- {
- CDemo localObjectInMain("LocalObjectInMain"); //2
- CDemo* pHeapObjectInMain = new CDemo("HeapObjectInMain"); //3
- cout << "In main, before calling func\n\n\n"; //4
- func();
- cout << "\n\n"; //13'
- func(); //staticObject静态对象已经存在,不再创建!
- cout << "\n\nIn main, after calling func\n"; //14
- //test作用域
- //staticObject.showObjectName(); //error C2065: “staticObject”: 未声明的标识符
- //cout << "In main, after GlobalObject.showObjectName(): ";
- //GlobalObject.showObjectName();
- return 0;
- }//15析构localObjectInMain //16析构staticObject //17析构GlobalObject
- </SPAN><SPAN style="COLOR: black"><SPAN style="FONT-FAMILY: Times New Roman; FONT-SIZE: 14px"> </SPAN></SPAN>
执行结果如下:
[结果分析,引申出四种对象]:
|
生存方式 |
执行时机 |
消亡时机 |
全局(静态)对象 |
全局静态存储区 global |
比程序进入点更早,构造函数先被执行; |
程序结束前,其析构函数被执行。 |
局部静态对象 |
局部静态存储区 local static |
在对象诞生时,其构造函数被执行。(注意,此处只会有一个实例产生,而且固定在内存上(非stack也非heap),它的构造函数在控制权第一次移转到其声明处时被调用。 |
程序将结束时(此对象因而将遭致毁灭)其析构函数才被执行,但比全局对象的析构函数更早一步执行。 |
局部对象 |
栈区 stack |
在对象诞生时,其构造函数被执行。(同局部静态对象) |
程序流程将离开该对象的存活范围时(以至于该对象将销毁)时,其析构函数被执行。 |
new方式产生的局部对象 |
堆区 heap |
当对象诞生时,其构造函数被执行。(同局部静态对象、局部对象) |
在对象被delete时执行析构函数。(注意,不加delete该heap区空间不会自动释放的,如果程序长期运行,会“吃掉”很多内存,造成结果不可预知。) |
[静态对象的深入探究(全局、局部)]
|
从产生抑制持续到程序结束的那些对象,在这个过程中不会动态的消亡,所以叫静态对象。 |
|
|
全局静态对象 |
局部静态对象 |
1.初始化时机 |
1)在main函数的代码前进行初始化; 2)类中静态、全局对象的初始化时机与该类的对象并无关系(强调:出现在类定义中的静态变量语句只是声明,对于要使用的类的静态成员变量,必须还要在类外进行定义,否则使用时会发生链接错误。声明并不会导致空间的分配,只有定义才会使其被生成。也就是如果你对类的静态成员进行了定义,那么它就肯定会被分配空间并初始化。就像全局变量一样); |
初始化发生在函数被调用期间,首次碰到该定义时。 |
2.举例(区分全局、局部静态对象) |
1)定义于namespace的对象; 2)在class 函数 file里的static对象; 3)类中的静态变量和全局变量; |
定义在函数里的为局部静态对象 |
3.如何实现的? |
对于non-local静态变量的初始化,编译器实际上是这样实现的。对每个编译文件里需要初始化的静态变量,生成一系列的sti_开头的函数,在里面完成初始化调用语句,然后把这些sti_函数抽取出来,形成一个初始化函数表,然后在__main()函数里调用,然后把这个函数放到main里的开头。 |
而对于local静态变量,为了实现第一次碰到时初始化,附加了一个全局变量,标志该对象是否被初始化,同时在析构时检查这个变量。这样就保证了第一次碰到时初始化,同时只有在执行了构造函数的时候,才会在程序退出时执行对应的析构函数。 |