1. malloc/free 与 new/delete 的区别?
身份:函数 运算符/关键字
返回值:void* 带类型的指针
参数:字符个数(手动) 类型(自动)
失败:NULL 抛异常std::bad_alloc
构造/析构:不调用 自动调用
初始化:不能初始化 可以初始化为指定值
头文件:包含头文件 直接使用
2. 现在有一块内存,如何让类、结构对象来使用这块内存
通过new来实现:
struct Student
{
char name[20];
char sex;
int id;
};
int main(int argc,const char* argv[])
{
char arr[28];
Student* stu = new(arr) Student;
printf("%p %p\n",arr,stu);
}
3.重载、重定义、重写的区别
重载:在同一作用域内,函数名相同,参数列表(参数的个数和类型)不同的函数构成函数重载。函数重载与返回值类型、参数名无关。
重定义:子类重新定义父类中有相同名称的非虚函数 ( 参数列表可以不同 ) 。
重写:是指子类重新定义父类虚函数(父类必须含有virtual关键字)的方法。父类与子类之间的多态性。
重载:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数。如,有两个同名函数:function func(p:integer):integer;和function func(p:string):integer;。那么编译器做过修饰后的函数名称可能是这样的:int_func、str_func。对于这两个函数的调用,在编译器间就已经确定了,是静态的。也就是说,它们的地址在编译期就绑定了(早绑定),因此,重载和多态无关!不能根据返回值判断两个函数是否构成重载。当函数构成重载后,调用该函数时,编译器会根据函数的参数选择合适的函数进行调用。
重定义:当两个函数构成重定义时,父类的同名函数会被隐藏,当用子类的对象调用同名的函数时,如果不指定类作用符,就只会调用子类的同名函数。如果想要调用父类的同名函数,就必须指定父类的域作用符。注意:当父类和子类的成员变量名相同时,也会构成隐藏。
重写:和多态真正相关。函数的函数名相同,参数也相同,但是函数的返回值可以不同(但必须只能是一个返回父类的指针(或引用)一个返回子类的指针(或引用)。当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。因此,这样的函数地址是在运行期绑定的(晚绑定)。
4.内联函数与宏函数的相同点和不同点
相同点:
都是采用了空间换时间的策略来提高程序的运行速度
不同点:
1、宏函数不是真正的函数,只是语句替换,不会对参数进行类型检查、没有返回值、不安全
2、内联函数是真正的函数,会严格检查参数类型、有返回值、比宏函数的安全性高
5.引用和指针使用场合
引用:引用是一种取别名的机制
什么情况下使用引用:
1、跨函数共享变量时,引用会比指针安全(不存在空引用,也极少出现野引用),比指针更方便(不需要取地址、解引用)
2、提高传参效率时,引用的传参效率比指针还要高,因为指针还需要4\8字节用于存储地址编号,而引用一个字节都不需要,但是引用与指针一样都有被修改的风险,因此为了保护目标需要增加const
使用引用需要注意的问题:
1、引用必须初始化,所以不存在空的引用
2、可以引用右值,但是必须使用const修饰
3、引用不能更改目标
4、返回值类型为引用类型时,不要返回局部变量的引用
指针:指针是一种存储他值地址以直接访问该值的一种变量
什么情况下使用指针:
1、跨函数共享变量(输出型参数),引用可代替
2、提高传参效率,引用可代替
3、配合堆内存使用,继续使用指针
4、配合字符串,string替代
6.指针与引用的相同点和不同点:
相同点:
都可以跨函数共享变量、都可以提高函数的传参效率、也都需要const保护
不同点:
1、引用是一种取别名机制,而指针是一种数据类型
2、引用是不需要额外的存储空间,而指针需要4/8字节用于存储地址编号
3、指针可以不初始化,但引用必须初始化
4、指针可以更改指向的目标,但引用不行
5、有空指针,但没有空引用
6、指针可以配合堆内存使用,而引用不可以
7、可以定义指针数组,但是不能定义引用数组(但可以定义数组指针,也可以定义数组引用,可以定义函数指针,也可以定义函数引用)
7.C++强制转换
C++存在强制转换,因此类型不安全。C++之父认为只有在程序设计不合理的情况下,才需要强制类型转换,之所以设计得复杂就是不想让程序员去用,希望程序员反思、重新设计自己的代码。
分为静态类型转换static_cast<目标类型>(原类型):目标类型于原类型之间必须要有一个方向可以自动类型转换,否则出错;
动态类型转换dynamic_cast<目标类型>(原类型):原类型和目标类型之间必须存在继承关系,否则会出错;
去常类型转换const_cast<目标类型>(原类型): 目标类型必须是指针或引用,且除了const属性外,其他都相同,否则会出错;
重解释类型转换reinterpret_cast<目标类型>(原类型):只能把整数转换成指针或把指针类型转换成整数,否则会出错
8.内存分配方式以及它们的区别?
1、从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static 变量。
2、 在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集。
3、 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc 或new 申请任意多少的内存,程序员自己负责在何时用free 或delete 释放内存。动态内存的生存期由程序员决定,使用非常灵活,但问题也最多。