1:初始化和赋值的区别?定义和声明的区别?
赋值操作是在两个已经存在的对象内进行,而初始化是要创建一个新的对象
赋值->调用重载的赋值运算符,
初始化->调用拷贝构造函数;
int i;//定义
int i=9;初始化
i= 7;// 赋值
从编译原理上来说,声明仅仅告诉编译器,有某个类型的变量会被使用,但编译器并不会为他分配任何内存,而定义是分配了内存
2:什么是"引用"?
引用是为已存在的变量取了一个别名,引用和引用的变量共用同一块内存空间
格式:类型& 引用变量名(对象名) = 引用实体; int& ia = a; ia为a的引用
2.1:指针和引用的区别?
相同点:都是地址的概念,指针是指向一块内存,它的内容是所指向内存的地址,引用是某块内容的地址
不同点:
①引用不分配内存区域,指针分配内存区域;
②指针是个实体,而引用仅是个别名;
③引用使用时无需解,指针需要解;
④引用只能被初始化时初始化一次,之后不可变,指针可变;
⑤引用不能为空,指针可以;
⑥引用sizeof是对象大小,指针sizeof是指针本身类型大小
⑦有多级指针,没有多级引用;
2.2:声明和使用引用需要注意哪些问题?
引用不是一种新的数据类型,因此它本身不占存储单元,系统也不会为它分配存储单元。
引用实体和引用类型必须为同种类型
引用在定义时必须初始化,对引用的操作就是对变量的直接操作
一个实体可以有多个引用,但一个引用只能引用一个实体,引用声明完毕后,相当于目标变量有两个名称----原名和引用名,不能把引用名再做为其他变量的的别名
int& ia; // 该条语句编译时会出错,引用定义时必须初始化
int& ia = a;
int& iia = a;
3:将引用作为函数返回值类型的格式,好处,和需要遵循的规则?
类型标识符 &函数名(形参列表及类型说明){ //函数体 }
int &number(const int a) { }
好处:在内存中不产生被返回值的副本;(注意:正是因为这点原因,所以返回一个局部变量的引用是不可取的。因为随着该局部变量生存期的结束,相应的引用也会失效,产生runtime error!
遵守的规则:
①不能返回局部变量的引用.
主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了"无所指"的引用,程序会进入未知状态。
②不能返回函数内部new分配的内存的引用。虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又面临其它尴尬局面。例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memory leak。
③可以返回类成员的引用,但较好是const。
4:new/delete和malloc/free的区别是什么?
①malloc是从堆上申请内存,new是从资源储存区申请内存;
②malloc返回值为void*,需要通过强制类型转换将void*指针转换成我们需要的类型,失败返回NULL;
new成功返回对象类型的指针,类型严格与对象匹配,无须进行类型转换,失败会抛出bac_alloc异常
③new会先调用operator new函数,申请足够的内存(通常底层使用malloc实现)。然后调用类型的构造函数,初始化成员变量,较后返回自定义类型指针。delete先调用析构函数,然后调用operator delete函数释放内存(通常底层使用free实现)。malloc/free是库函数,只能动态的申请和释放内存,无法强制要求其做自定义类型对象构造和析构工作。
④new分配内存无须制定内存大小
⑤malloc需要制定所需内存的大小
PS:
在C++中,内存区分为5个区,分别是堆、栈、自由存储区、全局/静态存储区、常量存储区;
在C中,C内存区分为堆、栈、全局/静态存储区、常量存储区;
5:内联函数和一般函数的区别在什么地方?
内联函数和普通函数的参数传递机制相同,但是编译器会在每处调用内联函数的地方将内联函数内容展开,这样既避免了函数调用的开销又没有宏机制的缺陷
普通函数在被调用的时候,系统首先要到函数的入口地址去执行函数体,执行完成之后再回到函数调用的地方继续执行,函数始终只有一个复制。
内联函数不需要寻址,当执行到内联函数的时候,将此函数展开,如果程序中有N次调用了内联函数则会有N次展开函数代码
5.1:内联函数,enum和宏定义的区别?
内联函数本质上是一个函数,内联函数一般用于函数体的代码比较简单的函数,不能包含复杂的控制语句,while、switch,并且内联函数本身不能直接调用自身。如果内联函数的函数体过大,编译器会自动的把这个内联函数变成普通函数。
宏定义是在预编译的时候把所有的宏名用宏体来替换,简单的说就是字符串替换内联函数则是在编译的时候进行代码插入,编译器会在每处调用内联函数的地方直接把内联函数的内容展开,这样可以省去函数的调用的开销,提率,
宏定义是没有类型检查的,无论对还是错都是直接替换
内联函数在编译的时候会进行类型的检查,内联函数满足函数的性质,比如有返回值、参数列表等宏定义和内联函数使用的时候都是进行代码展开。不同的是宏定义是在预编译的时候把所有的宏名替换,内联函数则是在编译阶段把所有调用内联函数的地方把内联函数插入。这样可以省去函数压栈退栈,提高了效率
#define 是预处理指令,是代码编译之前做的工作,仅仅做字符替换
枚举只能是int类型,enum默认常量在前一个值的基础上加1
ps:typedef:为类型命名一个别名 如:typedef unsigned int U32