天天看点

2017.02.29 C/C++小知识点

1. 函数重载: 指的是在同一作用域内,可以有一组相同函数名,不同参数列表的函数,这组函数被称为重载函数。通常用来命名一组功能相似的函数,减少了函数名的数量,避免了名字空间的污染,对于程序的可读性有很大的好处,方便用户使用。

2.main函数中如果无return,编译器会自动添加 return 0;

3. math.h中的abs函数的返回值:当num为最小负数时,abs(num)依然返回该最小负数。其他情况正常返回其绝对值

4. 预编译又称预处理,是做些代码文本的替换工作,是整个编译过程的最先做的工作。是为编译做的预备工作的阶段。处理“#”开头的指令,比如#include,#define,#pragma,#if等条件编译等;sizeof为操作符,与“+”、“-”等一样。malloc为函数,参数为字节数,返回一个void*指针。

5.switch语句: 当程序根据case值跳到switch中的特定代码后,将依次执行之后的所有语句。如果要让程序执行完一组特定语句后停止,必须使用break;

6. 结构体默认情况为8字节对齐。

7.数组作为函数参数传递是=时,退化为指针。void func(char str[100]){}这其中的100不起任何作用。

8. volatile的作用:避免编译器优化。当读取一个变量时,为提高存取速度,编译器优化时有时会先把变量读取到一个寄存器中;以后再取变量时,就直接从寄存器中取值。优化器在用到volatile变量时,必须每次都小心的重新读取这个值,而不是使用保存在寄存器里的备份。volatile适用于被所线程应用中被几个任务变量共享的变量。一个参数可以既是const又是volatile,如 const volatile int i=0;表示:任何对i的直接修改都是错误的,但是i可能被意外情况修改掉,不要做无意义的优化。

9.类型安全就是说,如果两个类型直接要相互转换,必须要显示的转换,不能只用一个等号就隐式转换了。std的string和MFC类库的CString之间可以通过CString的format方法进行转换。

10. STL中的vector是动态增加大小,所谓动态增加大小,并不是在原空间之后接续新空间(因为无法保证原空间之后尚有可控配置的空间),而是以原大小的两倍另外配置一块较大的空间,然后将原内容拷贝过来,然后才开始在原内容之后构造新元素,并释放原空间。所以vector在增加成员时可能会引起原有成员的存储位置发生。

11. 在类的继承中若要声明虚函数,则必须在基类中声明虚函数,在派生类中可以写virtual,也可以不写virtual(没有什么影响,但是最好能写上)。如果基类中没有声明virtual,则就算派生类中写了virtual,也不会是虚函数,而会是函数重载。

12. new/delete都是要分两步操作的:new分配内存,并且调用对象的构造函数初始化一个对象;delete调用相应的析构函数,然后释放内存;

      malloc/free只是分配/回收内存,new 是一个操作符,不需要头文件的支持,而malloc是一个函数,需要头文件“stdlib.h”或者“malloc.h”的支持。

13. 对于list型的数据结构,list是一个双向链表,使用了不连续分配的内存,删除运算使得指向删除位置的迭代器失效,但不会失效其他迭代器,解决办法有两种,erase(iter)会返回下一个有效迭代器的值,或者erase(iter++);对于数组型的数据结构,如vector,string,deque,erase(iter)的返回值是下一个有效迭代器的值。

14. 重写与重载的不同:(1) 重写(override)是子类和父类之间的继承关系,是垂直关系,重写的函数必须是virtual函数,即函数在原始的基类中被声明为虚函数。而方法的重载是同一个类中方法之间的关系,是水平关系;重写需要子类和父类中的两个函数函数原型完全相同;重载要求两个函数参数列表不同。重定义(redefine)指子类重新定义父类中的非虚函数,这样父类中的对应函数被隐藏。

15. 构造函数不能是虚函数。虚函数对应一个虚函数表,这个虚函数表是存储在对象的内存空间的,如果构造函数是虚的,就要通过虚函数表来调用,可是在构造函数调用之前,对象还没有实例化,还没有被构造出来,所以自然就找不到虚函数表,所以就无法调用虚函数,所以构造函数不能是虚函数。

从使用角度来看:构造函数使用虚函数是没有意义的。虚函数的作用在于通过父类的指针或者引用来调用它的时候能够变成调用子类的那个成员函数。而构造函数是在创建函数的时候自动调用的,不可能通过父类的指针或者引用去调用,因此也就规定构造函数不能是虚函数。

16. 创建派生类对象时,程序首先调用基类构造函数,然后再调用派生类构造函数。基类构造函数负责初始化继承的数据成员,而派生类构造函数主要用于初始化新增的数据成员。派生类的构造函数总是调用一个基类的构造函数。派生类对象过期时,程序首先调用派生类析构函数,然后再调用基类析构函数。

17. 派生类构造函数的执行顺顺序:调用基类构造函数,调用顺序按照它们被继承时声明的顺序(从左到右);然后对派生类新增的成员对象进行初始化;最后执行派生类自身的构造函数体中的内容。

18. 静态成员函数中不能出现this指针,所以静态成员函数不能调用类的非静态成员。

19. std::sort封装了快速排序算法,因此不是稳定的,若需要稳定的排序算法,则需要用std::stable_sort

20. 内联函数,主要为了提高程序运行速度,一般适用于不存在while和switch等复杂的结构且只有1~5条语句的小函数上。否则编译系统将该函数视为普通函数。递归函数不能定义为内联函数,否则会使代码变的很长,无限嵌套循环。

21. switch语句:(1) char、short 、int 、long、bool可以用于switch语句;(2)float、double都不能用于switch语句;(3) enum枚举类型可以用于switch语句;(4) 所有类型的对象都不能用于switch语句;(5) 字符串也不能用于switch语句。

22. C语言函数参数入栈顺序为由右向左。

23. 用户态切换到内核态的三种情况:(1) 系统调用 (2) 异常 (3) 外部设备的中断

24. #include<> 用来包含开发环境提供的库文件,而#include “”用来包含自己编写的头文件

25. 32位编译环境和64位编译环境下数据类型所占字节数是一样的,唯一不同的是指针类型:32位系统,指针类型占4个字节。64位系统,指针类型占8个字节。

26. 除了 . ,.*,::,?:,sizeof,typeid这几个运算符不能重载,其他运算符都可重载。(可记为 带点的运算符都不能重载)

继续阅读