C++基础知识点

C++中static关键字作用

  1. 函数体内static变量的作用域为该函数体,该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值
  2. 在模块内的static全局变量可以被模块内所用函数访问,但不能被模块外其他函数访问(在其他模块内调用需要使用using namespace)
  3. 在模块内的static函数只可被这一模块内的其它函数调用,这个函数的使用范围被限制在声明它的模块内
  4. 在类中的static成员变量属于整个类,不属于类的对象,所以它没有this指针,这就导致了它仅能访问类的静态成员和静态成员函数。同时不能将静态成员函数定义为虚函数。
    静态成员初始化与一般数据成员初始化不同: (1)初始化在类体外进行,而前面不加static,以免与一般静态变量或对象相混淆;
    (2)初始化时不加该成员的访问权限控制符private、public等
    (3)初始化时使用作用域运算符来标明它所属类,所以得出静态成员初始化格式:
<数据类型><类名>::<静态数据成员名>=<值> 为了防止父类的影响,可以在子类定义一个与父类相同的静态变量,以屏蔽父类的影响。 5. static关键字还有一个作用就是使得变量默认初始化为0,因为全局变量和静态变量都存储在静态数据区,静态数据区内存中所有字节的默认值都是0x00,比如将字符数组当做字符串使用时就会比较方便,因为尾元素的下一个字节就是'\0'。 ### C++和C的区别 1. 面向过程的思路:分析解决问题所需的步骤,用函数把这些步骤依次实现。 C语言是面向过程的编程,它最重要的特点是函数,通过main函数来调用各个子函数。程序运行的顺序都是程序员事先决定好的。 2. 面向对象的思路:把构成问题的事务分解为各个对象,建立对象的目的,不是完成一个步骤,而是描述某个事务在解决整个问题步骤中的行为。 C++是面向对象的编程,类是它的主要特点,在程序执行过程中,先由主main函数进入,定义一些类,根据需要执行类的成员函数,过程的概念被淡化了(实际上过程还是有的,就是主函数的哪些语句),以类驱动程序运行,类就是对象,所以我们称之为面向对象程序设计。面向对象在分析和解决问题的时候,将涉及到的数据和数据的操作封装在类中,通过类可以创建对象,以事件或消息来驱动对象执行处理。 3. C++对C的“增强”,表现在以下几个方面: 类型检查更为严格。增加了面向对象的机制。增加了泛型编程的机制(Template)。增加了异常处理。增加了运算符重载。增加了标准模板库(STL)。增加了命名空间,避免全局命名冲突。 4. C的大部分代码在C++上都能应用,而C++的代码在C上不能应用。(**记住是大部分,不是所有**)C++是C语言的超集,虽然C++兼容C,但是C++中也有与C语言中不兼容的地方。 5. C++与C不兼容之处: (1)变量声明的位置 C中变量声明和代码是分开的,必须在函数开始处声明; C++中,变量可以在任意处声明,只要保证先声名后使用的原则就可以。 (2)struct结构体 用struct定义变量`struct mystruct{ int i;float x;}`在c中声明struct变量要这么写:`struct mystruct a;`在C++中前面不用加struct:`mystruct a;`一种兼容的用法是:`typedef struct _mystruct{int i;float x;} mystruct;`然后用mystruct 定义变量。枚举型(enum),联合体类型(union)也是同样。 在C++中,struct结构体支持成员函数的定义,C中不行。另外要注意的是,C++中成员函数的默认访问说明符为public,这一点和类不同,类的默认访问说明符为private. (3)bool类型值 C++中有bool(或boolean类型);C中可没有这样的bool类型,均为数值类型!需要注意的是真为非零(如:1,52,-5,-2等),假的数值为0。 (4)注释的不同 C中的注释至有一种 /*......*/; C++中的注释包含两种/*......*/和//。 (5)强制数据类型装换 C中的强制转化形式为:(类型)变量; C++中还可以使用:类型(变量)的形式以及四种cast。 (6)函数 C语言中函数没有参数默认值,在C++中函数有参数默认值的概念,注意参数默认值与函数重载的区别。 C语言中函数的定义又两种形式,经典形式和标准形式,C++中只支持标准形式。 标准形式:`int string(int x,float y){......}` 经典形式: `int string(x,y)int x;float y;{......}` C++的函数必须先声名原型或定义才能使用,因为C++是强数据类型语言,在C语言中,未声名和定义函数之前调用函数是允许的. C语言中产生函数符号的规则是根据名称产生,这也就注定了c语言不存在函数重载的概念。而C++生成函数符号则考虑了函数名、参数个数、参数类型。需要注意的是函数的返回值并不能作为函数重载的依据,也就是说int sum和double sum这两个函数是不能构成重载的! 我们的函数重载也属于多态的一种,这就是所谓的静多态。 静多态:函数重载,函数模板 动多态(运行时的多态):继承中的多态(虚函数)。 (7)const C语言中的const:被修饰后不能做左值,可以不初始化,但是之后没有机会再初始化。不可以当数组的下标,可以通过指针修改。简单来说,它和普通变量的区别只是不能做左值而已。其他地方都是一样的。 C++中的const:真正的常量。定义的时候必须初始化,可以用作数组的下标。const在C++中的编译规则是替换(和宏很像),所以它被看作是真正的常量。也可以通过指针修改。需要注意的是,C++的指针有可能退化成C语言的指针。 ``` int b=20; const int a=b; ``` 这时候的a就只是一个普通的C语言的const常变量了,已经无法当数组的下标了。(引用了一个编译阶段不确定的值) (8)运算符& &运算符最基本的含义是取地址,C和C++中都支持这一语法。但在C++中&还可以表示引用。有了引用的概念后函数调用可以作为左值。例如: `int &rtux()......rtux()=5;` 以上表达式在C++中完全正确,但在C语言中是非法的。 引用底层就是指针,使用时会直接解引用,可以配合const对一个立即数进行引用。 (9)extern说明符 在C语言的某些版本中,可以在程序中多次使用一个全局变量而无需使用extern说明符。但在C++中除定义全局变量外,在其他模块使用应先用extern生明。 6. C++和C中struct的区别: (1)C中定义的时候需要在前面加上struct,而C++中不用 (2)C++把struct当成类处理,所以C++的struct中可以自己设定访问权限,而C中没有访问权限 (3)C++把struct当成类处理,所以C++中struct可以有成员函数,而C中不能有成员函数 (4)C++把struct当成类处理,所以C++中struct可以继承,而C中不能继承 7. C++中class和struct的区别: (1)struct作为数据结构的实现体,它默认的数据访问控制是public的,而class作为对象的实现体,它默认的成员变量访问控制是private的。 (2)class和struct如果定义了构造函数的话,都不能用大括号进行初始化。如果没有定义构造函数,struct可以用大括号初始化。如果没有定义构造函数,且所有成员变量全是public的话,可以用大括号初始化。 (3)class继承默认是private继承,而struct继承默认是public继承。 8. C++保留struct关键字原因: (1)保证与C语言的向下兼容性,C++必须提供一个struct (2)C++中的struct定义必须百分百地保证与C语言中的struct的向下兼容性,把C++中的最基本的对象单元规定为class而不是struct,就是为了避免各种兼容性要求的限制 (3)对struct定义的扩展使C语言的代码能够更容易的被移植到C++中 ### new/delete和malloc/free的区别 1. malloc是从堆上开辟空间,而new是从自由存储区开辟;(自由存储区是C++抽象出的概念,不仅可以是堆,还可以是静态存储区) 2. malloc/free是函数,而new/delete是关键词或者说是运算符 3. malloc对开辟的空间大小需要严格指定,而new只需要对象名 4. malloc开辟的空间既可以给单个对象用也可以给数组用,释放的方式都是free;而new开辟对象数组用的是new[size],释放的方式是delete[](尽管内置类型可能不会引起问题,但是自定义类型的话,delete[]需要知道有多少个对象,而这个计数就被放在这块空间的头部) 5. 返回值问题,malloc开辟成功返回void*,需要强制类型转换,失败返回NULL,new成功返回对象指针,失败抛出异常,虽然为了最大程度兼容C,C++new也支持失败返回NULL,但一般不被使用 6. 是否调用构造函数和析构函数,new和free不但负责开辟空间,当使用了自定义类型时还会调用对象的构造函数和析构函数,而malloc/free则不会 7. 是否可以相互调用,new的实现可以用malloc,malloc的实现不可以使用new; 8. 是否可以被重载,new operator/delete operator就是new和delete操作符,而operator new/operator delete是函数。我们可以重载自己的operator new/delete,但是不可以重载new/delete/malloc/free; 9. malloc开辟 的内存如果太小,想要换一块大一点的,可以调用relloc实现,但是new没有直观的方法来改变; 10. 当new中的底层实现如果获取不到更多的内存,会触发new_handler机制,留有一个set_new_handler句柄,看看用户是否设置了这个句柄,如果设置了就去执行,句柄的目的是看看能不能尝试着从操作系统释放点内存,找点内存,如果实在不行就抛出bad_alloc异常;而malloc就没有这种尝试了; ### new运算符、operator new、placement new的区别与联系 1. new的执行过程: (1)通过operator new申请内存 (2)使用placement new调用构造函数(内置类型忽略此步) (3)返回内存指针 2. delete的执行过程: (1)调用析构函数(内置类型忽略此步) (2)使用operator delete释放内存 3. new运算符: (1)调用operator new分配足够的空间 (2)不可以被重载 4. operator new: (1)只分配所要求的空间,不调用相关对象的构造函数。当无法满足所要求分配的空间时,则: 如果有new_handler,则调用new_handler,否则如果没要求不抛出异常(以nothrow参数表达),则执行bad_alloc异常,否则返回0 (2)可以被重载 (3)重载时,返回类型必须为void* (4)重载时,第一个参数必须为表达要求分配空间的大小(字节),类型为size_t (5)重载时,可以带其它参数 delete与operator delete类似 5. ::operator new是全局函数,这样的全局函数有三个,其中有一个就是placement new。一般用户不会(虽然能)在全局重载operator new函数,而是在自定义的类中重载operator new函数。operator new都是申请一个对象的空间内存,所以调用的时候size_t省略,但是对于operator new[]这个函数要明确说明数组中对象的个数。 6. new和delete操作符是对自由存储区的内存进行申请和释放,而这两个都是不能被重载的,要实现不同的内存分配行为,需要重载operator new和operator delete,而不是new和delete。 7. 我们不能在全局对原型为`void operator new(size_t size)`这个原型进行重载,一般只能在类中重载,如果类中没有重载operator new,那么调用的就是全局的::operator new来完成内存的分配。 8. palcement new是operator的一个重载版本,如果我们想在已经分配的内存中创建一个对象,使用new是行不通的,palcement new允许我们在一个已经分配好的内存中构造一个新的对象。原型中void *p就是指向一个已经分配好的内存缓冲区的地址。 9. 使用new操作符分配内存需要在自由存储区中查找足够大的剩余空间,操作速度很慢,而且有可能出现无法分配内存的异常(空间不够)。而使用palcement new,我们构造对象都是在一个预先准备好了的内存缓存区中进行,不需要查找内存,内存分配时间为常数,而且不会出现程序运行中内存不足的异常。 10. 一旦使用placement new创建的对象使用完毕,我们必须显式调用类的析构函数进行销毁对象,此时内存空间不会被释放,以便其他对象的构造。 ``` myclass {}; char *a=new char[100*sizeof(myclass)];//预先分配内存 myclass *p=new(a) myclass;//使用placement new函数 p->~myclass();//显式调用析构函数 ``` 11. 全局有三个operator new函数,分别如下: ``` 1: void* operator new (std::size_t size) throw (std::bad_alloc); 2: void* operator new (std::size_t size, const std::nothrow_t & nothrow_constant) throw(); 3: void* operator new (std::size_t size, void* ptr) throw();  ``` 第一种分配size个字节的存储空间,并进行对象类型进行内存对齐。如果成功,返回一个非空的指针指向首地址。失败抛出bad_alloc异常。 第二种在分配失败时不抛出异常,它返回一个NULL指针。 第三种是placement new版本。它不分配内存,调用合适的构造函数在ptr所指的地方构造一个对象,之后返回实参指针ptr。 三种版本的operator new 定义在全局命名空间,不在std中。第一、第二个版本C++默认在每个编译单元中声明,不需要`#include `头文件。第一、第二个版本可以被用户更换和重载(一般在类中重载),定义自己的版本,第三种placement new不可重载。 12. new的本质是关键字,编译器在背后的操作可能与我们的想象大不相同。能够重载的是函数,是运算符,关键字是不能重载的 ### char*、char**、char[]和char *a[]的区别 1. 当定义 char a[10] 时,编译器会给数组分配十个单元,每个单元的数据类型为字符,而定义 char *s 时, 这是个指针变量,只占四个字节,32位,用来保存一个地址 2. `char *a[]`,由于\[\]的优先级高于\*,所以a先与\[\]结合,它还是一个数组,但是里面的元素类型是`char*` 3. `char** a`为二级指针,a中保存一级指针`char *`的地址