多玩YY语音的面试题:C++中如何在main()函数之前执行操作?

简介: 第一反应main()函数是所有函数执行的开始。但是问题是main()函数执行之前如何执行呢? 联想到MFC里面的 C**App类的theApp对象,其执行顺序就在main函数之前。道理相通,顺理推下,能够想到:如果在main函数之前声明一个类的全局的对象。那么其执行顺序,根据全局对象的生存期和作用域,肯定先于main函数。

多玩YY语音的面试题:C++中如何在main()函数之前执行操作?


          第一反应main()函数是所有函数执行的开始。但是问题是main()函数执行之前如何执行呢?


          联想到MFC里面的 C**App类的theApp对象,其执行顺序就在main函数之前。道理相通,顺理推下,能够想到:如果在main函数之前声明一个类的全局的对象。那么其执行顺序,根据全局对象的生存期和作用域,肯定先于main函数。


示例如下:


class simpleClass

{

public:

      simpleClass( )

      {

             cout << "simpleClass constructor.." << endl;  //step2

      }

};

simpleClass g_objectSimple;         //step1全局对象

int _tmain(int argc, _TCHAR* argv[])  //step3

{

      return 0;

}

可单步调试查看执行顺序为step1、step2、step3。


考虑到全局对象,同理会进一步思考静态对象的作用域。将上述示例进一步扩展如下:


class simpleClass

{

public:

      simpleClass( )

      {

             cout << "simpleClass constructor.." << endl;       //step2

      }

};

class simpleClassTwo

{

public:

      static simpleClass m_sSimpleClass;

};

simpleClass simpleClassTwo::m_sSimpleClass = simpleClass(); //step1 静态对象

int _tmain(int argc, _TCHAR* argv[])                        //step3

{

       return 0;

}

可单步调试查看执行顺序为step1、step2、step3。

       至此,我们可以总结出:定义在main( )函数之前的全局对象、静态对象的构造函数在main( )函数之前执行。


     再进一步思考,既然可以在main( )函数之前执行全局、静态对象的构造函数。那么有没有函数在main( )函数之后执行呢?


有的,onexit函数。原型如下:


_onexit_t _onexit(


  _onexit_t function


);


_onexit_t_m _onexit_m(


  _onexit_t_m function


);


解释:The _onexit function is passed the address of a function (function) to be called when the program terminates normally. Successive calls to _onexit create a register of functions that are executed in LIFO (last-in-first-out) order. The functions passed to _onexit cannot take parameters.



核心点:


1)              执行期——程序执行终止的时候;


2)              传递参数——函数的地址,即函数指针;


3)              执行顺序——后进先出。



_onexit is a Microsoft extension. For ANSI portability, use atexit. The _onexit_m version of the function is for mixed mode use.


onexit是微软的扩展版本,标准C++里面应用的是atexit。


【MSDN】示例:


#include <stdlib.h>

#include <stdio.h>

/* Prototypes */

int fn1(void), fn2(void), fn3(void), fn4 (void);

int main( void )

{

     _onexit( fn1 );

     _onexit( fn2 );

     _onexit( fn3 );

     _onexit( fn4 );

     printf( "This is executed first.\n" );

}

int fn1()

{

     printf( "next.\n" );

     return 0;

}

int fn2()

{

     printf( "executed " );

     return 0;

}

int fn3()

{

     printf( "is " );

     return 0;

}

int fn4()

{

     printf( "This " );

     return 0;

}

执行结果如下:

————————————————

版权声明:本文为CSDN博主「铭毅天下」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/laoyang360/article/details/8820501

相关文章
|
8天前
|
Linux 编译器 Shell
拼多多面试 Linux下一个应用程序开始执行到main被调用之间经历了什么?
在Linux中,程序启动到`main`调用涉及加载器、内核、动态链接器和C运行时。`execve`系统调用加载ELF文件,内核创建进程,加载段,设置栈和调用动态链接器。动态链接器解析符号,重定位,执行初始化。C运行时初始化堆栈,调用`main`。从`_start`到`main`的流程包括环境设置和函数调用。
27 0
|
9天前
|
存储 C++
【C++】string类的使用③(非成员函数重载Non-member function overloads)
这篇文章探讨了C++中`std::string`的`replace`和`swap`函数以及非成员函数重载。`replace`提供了多种方式替换字符串中的部分内容,包括使用字符串、子串、字符、字符数组和填充字符。`swap`函数用于交换两个`string`对象的内容,成员函数版本效率更高。非成员函数重载包括`operator+`实现字符串连接,关系运算符(如`==`, `&lt;`等)用于比较字符串,以及`swap`非成员函数。此外,还介绍了`getline`函数,用于按指定分隔符从输入流中读取字符串。文章强调了非成员函数在特定情况下的作用,并给出了多个示例代码。
|
9天前
|
算法 C++ 容器
|
9天前
|
存储 编译器 程序员
|
10天前
|
存储 编译器 文件存储
|
14天前
|
编译器 C++
【C++】类和对象③(类的默认成员函数:赋值运算符重载)
在C++中,运算符重载允许为用户定义的类型扩展运算符功能,但不能创建新运算符如`operator@`。重载的运算符必须至少有一个类类型参数,且不能改变内置类型运算符的含义。`.*::sizeof?`不可重载。赋值运算符`=`通常作为成员函数重载,确保封装性,如`Date`类的`operator==`。赋值运算符应返回引用并检查自我赋值。当未显式重载时,编译器提供默认实现,但这可能不足以处理资源管理。拷贝构造和赋值运算符在对象复制中有不同用途,需根据类需求定制实现。正确实现它们对避免数据错误和内存问题至关重要。接下来将探讨更多操作符重载和默认成员函数。
|
6天前
|
C++
C++友元函数和友元类的使用
C++中的友元(friend)是一种机制,允许类或函数访问其他类的私有成员,以实现数据共享或特殊功能。友元分为两类:类友元和函数友元。类友元允许一个类访问另一个类的私有数据,而函数友元是非成员函数,可以直接访问类的私有成员。虽然提供了便利,但友元破坏了封装性,应谨慎使用。
39 9
|
1天前
|
设计模式 安全 编译器
【C++11】特殊类设计
【C++11】特殊类设计
22 10