面试知识点准备-C++常见问题

博客园写写格式简单的文章还行,格式一复杂就不行了,可能是我不会用吧,我有强迫症,有道云格式很好用,以后去有道写这种东西了

有道云笔记链接:http://note.youdao.com/noteshare?id=6e9d2c03cd00b31ffc35c34fc2937d2c&sub=009B96AB6E0E429D980513D21226455D

常见问题:

  • static:
    • 隐藏:修饰全局函数、全局变量。当同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性。
    • 保持变量内容的持久:存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。共有两种变量存储在静态存储区:全局变量和static变量,只不过和全局变量比起来,static可以控制变量的可见范围,说到底static还是用来隐藏的。虽然这种用法不常见。如果作为static局部变量在函数内定义,它的生存期为整个源程序,但是其作用域仍与自动变量相同,只能在定义该变量的函数内使用该变量。退出该函数后, 尽管该变量还继续存在,但不能使用它。把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域, 限制了它的使用范围。
    • static变量默认初始化为0:全局变量也具备这一属性,因为全局变量也存储在静态数据区。在静态数据区,内存中所有的字节默认值都是0x00,某些时候这一特点可以减少程序员的工作量。比如初始化一个稀疏矩阵,我们可以一个一个地把所有元素都置0,然后把不是0的几个元素赋值。如果定义成静态的,就省去了一开始置0的操作。再比如要把一个字符数组当字符串来用,但又觉得每次在字符数组末尾加‘\0’;太麻烦。如果把字符串定义成静态的,就省去了这个麻烦,因为那里本来就是‘\0’。
    • 修饰类成员:

      • 初始化时使用作用域运算符来标明它所属类,静态数据成员是类的成员,而不是对象的成员。
      • 类的静态成员函数是属于整个类而非类的对象,没有this指针,只能访问类的静态数据和静态成员函数。
      • 不能将静态成员函数定义为虚函数。
      • 由于静态成员声明于类中,操作于其外,所以对其取地址操作,变量地址是指向其数据类型的指针 ,函数地址类型是一个“nonmember函数指针”。
      • 由于静态成员函数没有this指针,所以就差不多等同于nonmember函数,结果就 产生了一个意想不到的好处:成为一个callback函数,使得我们得以将C++和C-based X Window系统结合,同时也成功的应用于线程函数身上。 
      • static并没有增加程序的时空开销,相反她还缩短了子类对父类静态成员的访问 时间,节省了子类的内存空间。      
      • 静态数据成员是静态存储的,所以必须对它进行初始化。 (程序员手动初始化,否则编译时一般不会报错,但是在Link时会报错误)
      • 静态成员初始化在类体外进行,与一般数据成员初始化不同:,为了防止父类的影响,可以在子类定义一个与父类相同的静态变量,以屏蔽父类的影响。这里有一点需要注意:我们说静态成员为父类和子类共享,但我们有重复定义了静态成员,这会不会引起错误呢?不会,我们的编译器采用了一种绝妙的手法:name-mangling 用以生成唯一的标
  • const :
    • 修饰变量:阻止变量被更改,const int a=10;<=>int const a=10;
    • 修饰指针:const位于*左侧,修饰所指对象,为底层const(可以表示任意对象是常量);const位于*右侧,修饰指针,为顶层const
    • 修饰引用:不能通过该引用修改变量
    • 与函数相关:
      • 修饰函数参数:传递过去的参数在函数内不能修改(注意顶层或底层指针)
      • 修饰函数返回值:用const修饰函数返回值的含义和用const修饰普通变量以及指针的含义基本相同。
    • 与类相关:
      • 修饰类成员变量:成员常量,只能在类的构造函数初始化列表中赋值,不能在类构造函数体内赋值。
      • 修饰类成员函数:函数体内不能改变该类对象的任何成员变量, 也不能调用类中任何非const成员函数;const成员函数能够访问对象的const成员,而其他成员函数不可以(限定修饰符?)。
      • 修饰类对象/对象指针/对象引用:const对象中的任何成员都不能被修改。const对象的任何非const成员函数都不能被调用,因为任何非const成员函数会有修改成员变量的企图。
  • extern:
    • 与"C"连用时:如: extern "C" void fun(int a, int b);则告诉编译器在编译fun这个函数名时按着C的规则去翻译相应的函数名而不是C++的,C++的规则在翻译这个函数名时会把fun这个名字变得面目全非
    • 修饰变量或函数时:声明函数或全局变量的作用范围的,其声明的函数和变量可以在本模块或其他模块中使用(描述不当,待修改)
  • volatile:
    • 类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。声明时语法:int volatile vInt; 当要求使用 volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。
  • 四种类型转换
    • static_cast:
    • dynamic_cast:
    • const_cast:
    • reinterpret_cast:
  • new、delete与malloc、free:
    • delete会调用对象的析构函数,和new对应free只会释放内存,new调用构造函数。
    • malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。对于非内部数据类型的对象而言,光用malloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。
  • delete与delete[]的区别:
    • delete只会调用一次析构函数,而delete[]会调用每一个成员的析构函数。
  • define与const:
    • 编译器处理方式:
      • define在预处理阶段进行替换
      • const在编译时确定其值
    • 类型检查:
      • define无类型,不进行类型安全检查,可能会产生意想不到的错误
      • const有数据类型,编译时会进行类型检查
    • 内存空间 :
      • define不分配内存,给出的是立即数,有多少次使用就进行多少次替换,在内存中会有多个拷贝,消耗内存大
      • const在静态存储区中分配空间,在程序运行过程中内存中只有一个拷贝
    • 用define可以定义一些简单的函数,const是不可以定义函数的.
    • 其他:
      • 在编译时, 编译器通常不为const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高
      • 宏替换只作替换,不做计算,不做表达式求解。
      • 宏定义的作用范围仅限于当前文件
      • 默认状态下,const对象只在文件内有效,当多个文件中出现了同名的const变量时,等同于在不同文件中分别定义了独立的变量。如果想在多个文件之间共享const对象,必须在变量定义之前添加extern关键字(在声明和定义时都要加)。
  • 内联函数:
    • 定义:定义在类体内的成员函数,即该函数的函数体放在类体内。
    • 引入原因:解决程序中函数调用的效率问题,宏的定义很容易产生二意性。
    • 取代宏的原因:
      • inline 定义的类的内联函数,函数的代码被放入符号表中,在使用时直接进行替换,(像宏一样展开),没有了调用的开销,效率很高。
      • 类的内联函数也是一个真正的函数,编译器在调用一个内联函数时,会首先检查它的参数的类型,保证调用正确。然后进行一系列的相关检查,就像对待任何一个真正的函数一样。消除了它的隐患和局限性。inline 可以作为某个类的成员函数,可以在其中使用所在类的保护成员及私有成员。
    • 内联函数和宏的区别:
      • 宏由预处理器进行替代,内联函数通过编译器控制实现。内联函数是真正的函数,只是在需要用到的时候,像宏一样展开,减少了调用的开销。你可以象调用函数一样来调用内联函数,而不必担心会产生于处理宏的一些问题。
      • 代码效率相同,但内联函数优于宏定义,内联函数遵循的类型和作用域规则,它与一般函数更相近,在一些编译器中,一旦关上内联扩展,将与一般函数一样进行调用,比较方便。
    • 什么时候需要内联函数:
      • 应用最广的是用来定义存取函数。类中一般会把数据成员定义成私有的或者保护的。对于私有或者保护成员的读写就必须使用成员接口函数来进行。如果我们把这些读写成员函数定义成内联函数的话,将会获得比较好的效率。
    • 内联函数的局限性:
      • 内联函数也有一定的局限性。就是函数中的执行代码不能太多了,如果,内联函数的函数体过大,一般的编译器会放弃内联方式,而采用普通的方式调用函数。(换句话说就是,你使用内联函数,只不过是向编译器提出一个申请,编译器可以拒绝你的申请)
    • 使用注意事项:
      • 在内联函数内不允许用循环语句和开关语句。
      • 内联函数的定义必须出现在内联函数第一次被调用之前。
  • 多态性与虚函数表
    • 多态的实现  
    • 虚函数的作用
    • 动态绑定
    • 虚函数实现机制
    • 菱形继承
    • 继承与组合
  • C++11部分新特性
    • auto、lambda、decltype、constexpr
    • 智能指针
    • share_ptr
    • unique_ptr
    • weeak_ptr
    • 正则表达式
上一篇:BZOJ 2219: 数论之神


下一篇:phpstorm10.0.1和webstorm11注册