关于C++的面试题

来源:互联网 发布:手机淘宝投诉电话多少 编辑:程序博客网 时间:2024/06/04 17:52

一、谈一谈static

      这个问题不算太难,但是要完整的把static的作用说完还是有一定难度的。

A、首先解释static在C语言中的作用,这些作用在C++中被完全继承了。

(1)所有使用static修饰过的变量如果未被显式初始化,则被存储在bss段,BSS段在二进制程序中是没有实际存储的,

只有在程序运行时才会为BSS段分配内存同时进行默认初始化 ,在C语言中也就是赋值为0 。如果显示初始化了,

那么就存储在data段。而不管是bss段还是data段,其生命周期都是全局的,所谓全局就是main函数执行之前他们已被初始化,

在main函数执行结束,他们的内存才被清理。

(2)对与定义在函数内部的static变量,他们的访问权限仍然只在本函数内部,由于生命周期是全局的,所以每一次函数调用,

他们的值都保留上一次调用的结果,如果第一次调用,则未初始化的值。同样,由于static变量被每次函数调用所共享 , 

因此如果一个定义了static变量的函数被多个线程调用了,就会出现不一致状态。这种函数在多线程中被称之为不可重入函数,

如果没有保护措施,是不能直接在多线程中调用的。

(3)对于函数和全局变量,static声明是得该函数或者变量只能被本文件访问,不能被其他文件访问,

C语言一般使用这个特性来实现信息的隐藏。

B、再说C++中static除C语言之外的特性。

(1)第一点其实不算是特性,指的是static的非pure_data对象,这种对象的生命周期任然是全局的,

也就是说他们的构造函数在main函数之前执行,析构函数在main函数之后执行。

 (2)定义在类中的static成员对象和成员函数是被整个类共享的,而不是特定对象的。

二、关于const的实现

   同样先追溯到c语言中的const(好像只有c99新标准才支持const,姑且就用它先来解释),

c语言中没有类和对象以及引用一说,因此const只用来修饰变量(实际上修饰后变成了常量)。

先上一段代码:

#include<stdio.h>int main(int argc , char *argv[]){    const int a = 100;    int *p = (int*)&a;    *p = 0;    printf("a = %d , *p = %d \n" , a , *p);    return 0;}

运行结果:

a = 0 , b = 0

由此看来C语言中的const修饰过的变量是可以改变的,也就是说他们的存储机制和普通变量是一摸一样的,

说他们修饰过的变量不能改只是编译器在编译期间根据C语言语法规则做了限制而已,通过某些奇技淫巧(如上例)还是可以修改的,

当然实际项目中是绝对不允许这么做的。

那么C++是不是继承了这个机制了呢?我们再看一段代码:

#include<iostream>using namespace std;int main(int argc , char *argv[]){    const int a = 100;    int *p = (int*)&a;    *p = 0;    cout<<"a = "<<a<<" , *p = "<<*p<<endl;    cout<<"&a = "<<&a<<" , p = "<<p<<endl;    return 0;}

运行结果:

a = 100 , *p = 0&a = 0xffc18028 , p = 0xffc18028
那么这是怎么一回事呢?其实这就是所谓的常量折叠,指的是在编译期间将常量用他们的值来代替,

类似于宏定义,但是和宏定义最大的区别是宏定义在预处理阶段替换完以后所有出现宏名的地方都被

替代为宏的值,宏名完全消失,这也是C++中为什么不建议使用宏的原因,因为宏名消失后难于调试。

那么用const修饰过的变量呢?首先,这些变量的替换是在编译的时候才进行的,变量名被添加到了符号

表,所以方便调试。而是为这些变量分配了内存空间,从上面的程序中就可以看出a其实是有内存空间的。

那么为什么他的内存空间通过指针p修改后他的值没有改变呢?刚才说了,编译期间已经替换为初始化他

的值了,也就是说cout<<"a = "<<a<<" , *p = "<<*p<<endl;这句话在编译期间被替换为

cout<<"a = "<<100<<" , *p = "<<*p<<endl;


我们知道volatile可以拒绝编译器的优化,让其永远从内存读取,那么我们再来看一段代码:

#include<iostream>  
  

using namespace std;  int main(int argc , char *argv[])  {      volatile const int a = 100;      int *p = (int*)&a;      *p = 0;        cout<<"a = "<<a<<" , *p = "<<*p<<endl;      cout<<"&a = "<<&a<<" , p = "<<p<<endl;      return 0;  }  


输出结果:

a = 0 , *p = 0

&a=0xffc18028 , p = 0xffc18028

看来编译器这次确实是从内存读取a的值的,a的值也确实发生了变化。

那么C++中修饰成员函数的const是怎么实现的呢?同样看一段代码:

class Hehe{public:   Hehe(int x = 0) : x_(x){}   void hfunc(Hehe *hp)const   {          hp->x_ = 100;   }  int getx()const  {         return x_;  }private:    int x_;};int main(int argc , char *argv[]){Hehe h;h.hfunc(&h);cout<<h.getx()<<endl;}

程序执行结果:100

呵呵,看来C++编译器是如此好骗,修饰成员函数的const也就是编译器执行了一下语法检查而已,今天就到这里。


0 0
原创粉丝点击