rambo

面试语法糖C++(三)

一、static静态变量与全局变量的区别

1)变量会被放在程序的全局存储区中,这样可以在下一次调用的时候还可以保持原来的赋值。这一点是它与栈变量和堆变量的区别。

  • 栈存放的是局部变量、函数的参数等。栈是有限的,尽量不要存放大数据,比如char str[2048],其他都可以。
  • 堆就是malloc、new后得到的内存空间。

2)变量用static告知编译器,自己仅仅在变量的作用范围内可见。这一点是它与全局变量的区别。

A、若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度;

(用算法代替各种if-else,用functor(仿函数)代替各种class。)
B、若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度;
C、设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题;
D、如果我们需要一个可重入的函数,那么,我们一定要避免函数中使用static变量(这样的函数被称为:带“内部存储器”功能的的函数)

E、函数中必须要使用static变量情况:比如当某函数的返回值为指针类型时,则必须是static的局部变量的地址作为返回值,若为auto类型,则返回为错指针。

函数前加static使得函数成为静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件(所以又称内部函数)。使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名。

补充知识:可重入函数在 实时系统的设计中,经常会出现多个任务调用同一个函数的情况。如果这个函数不幸被设计成为不可重入的函数的话,那么不同任务调用这个函数时可能修改其他任 务调用这个函数的数据,从而导致不可预料的后果。那么什么是可重入函数呢?所谓可重入是指一个可以被多个任务调用的过程,任务在调用时不必担心数据是否会 出错。可重入函数或者只使用局部变量,即保存在CPU寄存器中或堆栈中;或者使用全局变量,则要对全局变量予以保护。不可重入函数在实时系统设计中被视为不安全函数。

满足下列条件的函数多数是不可重入的:
(1)函数体内使用了静态的数据结构;
(2)函数体内调用了malloc()或者free()函数;
(3)函数体内调用了标准I/O函数。

二、静态数据成员:

类体中的数据成员的声明前加上static关键字,该数据成员就成为了该类的静态数据成员。和其他数据成员一样,静态数据成员也遵守public/protected/private访问规则。同时,静态数据成员还具有以下特点:
1)静态数据成员的定义。
静态数据成员实际上是类域中的全局变量。所以,静态数据成员的定义(初始化)不应该被放在头文件中

其定义方式与全局变量相同。(和构造函数没有半毛钱)

2)静态数据成员被 类 的所有对象所共享,包括该类派生类的对象。即派生类对象与基类对象共享基类的静态数据成员。

3)静态数据成员的类型可以是所属类的类型,而普通数据成员则不可以。普通数据成员的只能声明为 所属类类型的 指针或引用。举例如下:

三、静态函数在类内与类外的区别

静态函数:函数前加static使得函数成为静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件(所以又称内部函数)。

静态成员函数:使用类的静态成员函数来访问类的私有静态数据成员。

静态成员函数的声明除了在类体中的函数声明前加上关键字static, 以及不能声明为const volatile之外,与非静态成员函数相同。出现在类体外的函数定义不能指定关键字static

静态成员函数没有this 指针,因此在静态成员函数中,隐式或显式地引用这个指针都将导致编译时刻错误。试图访问隐式引用this 指针的非静态数据成员也会导致编译时刻错误。

CALLBACK函数必须定义为静态函数。(有待研究)

四、override、overload(重载)和overwrite的区别

C++:

函数重载(overloading):定义几个功能相似而但参数或返回值不同(包括类型、顺序不同)的函数,那么这几个函数可以使用相同的函数名。(1)相同的范围(在同一个类中);(2)virtual 关键字可有可无。

(3)const成员函数可以和非const成员函数形成重载;

当某个函数中调用重载函数时,编译器会根据实参类型调用相应的函数:1)如果有严格匹配的函数,调用之;2)参数内部转换后如果匹配,调用之;3)通过用户定义的转换寻求匹配。

函数覆盖(overriding):指在继承时,父类函数声明为 virtual , 子类重新声明和实现该函数(函数名和参数完全相同,返回值不做约束)。子类该函数可以声明为 virtual ,也可以不加,不做限制,但是如果该子类还会继续被重载,则最好也声明为 virtual 。
(1)不同的范围(分别位于派生类与基类);
(2)函数名字相同;
(3)参数相同;
(4)基类函数必须有virtual 关键字。

virtual机制是使用虚表(vtable)实现的,虚表维护一个虚函数指针列表,当一个对象的某个虚函数被调用的时候,去虚表中查找并决定调用的是哪个函数。

函数重写(overwriting)是指派生类的函数屏蔽了与其同名的基类函数。其实现机制和Override完全不同,且会导致问题,应该避免使用。
(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。