C/C++面试拷问灵魂知识点(只给出标题和简单的解答 持续更新)
C/C++面试拷问灵魂知识点(只给出标题和简单的解答 持续更新)
相关的链接
C/C++:
https://www.cnblogs.com/hcr1995/p/9646379.html
https://blog.****.net/kuweicai/article/details/82779648
c++指针问题(比如指针的初始化问题)
没有初始化的指针应该指到null去;
释放了内存的指针,也应该指到null去。
c++中const问题
c++中static问题
C++中有了malloc / free , 为什么还需要 new / delete
malloc是库函数,而new是运算符。对象在创建的时候需调用构造函数,对象在释放的时候,需要调用析构函数。由于malloc是函数,所以不能由编译器把构造和析构的功能强加给malloc。而使用new的时候,会自动的调用构造函数,使用delete的时候会自动的调用析构函数。所以不要试图使用malloc来管理对象内存,而应该使用malloc。
那反过来说,已经有了new/delete了为什么还要malloc/free。
因为c++中经常需要调用c中的代码,所以需要malloc/free。
类的静态成员变量和静态成员函数各有哪些特性✳
静态成员变量属于整个类所有,所有对象共享类的静态成员变量
静态成员变量的生命周期不依赖于任何对象
可以通过类名和对象名访问public静态成员变量
静态成员变量的定义:
静态成员变量在类的内部声明,声明时直接通过static关键字修饰
静态成员变量在类的外部定义与初始化,语法规则为Type ClassName::VarName = value;
静态成员变量不占用类的大小,而是在类外(全局数据区)单独分配空间
与静态成员变量类似,静态成员函数是类中特殊的成员函数:
静态成员函数属于整个类所有
可以通过类名和对象名访问public静态成员函数
静态成员函数只能访问静态成员变量和静态成员函数
private static 和 public static 都是静态变量,在类加载时就定义,不需要创建对象。但是private static 是私有的,不能在外部访问,只能通过静态方法调用,这样可以防止对变量的修改。
父类的static变量和函数在派生类中依然可用,但是受访问性控制(比如,父类的private域中的就不可访问),而且对static变量来说,派生类和父类中的static变量是共用空间的,这点在利用static变量进行引用计数的时候要特别注意。
几个对比的问题:
指针和引用:
- 指针保存一个地址值,而引用时存储空间的一个别名,在底层实现上是一样的,引用也是使用指针实现的。
- 指针可以修改指向的地址,引用一次初始化之后,不可以修改
- 指针可以指向空地址,引用不可以
- 指针可以实现多级指针,以用不可以
- 指针的sizeof时指针的大小,引用的sizeof是指向的存储空间的大小
- 指针的++和引用的++意义不一样,指针引用时按照类型加一个类型空间,也就是指向该指针类型的下一个空间。如果是引用,则跳过所指向的这片区域,到所指区域的后一个位置
- 指针使用的时候需要使用*号解析,引用不需要解析,直接使用
malloc/free和new/delete
- malloc是库函数;new是运算符
- malloc分配的空间和new分配的空间所在的地方可能有区别,但是在c++中一般是一样的
- 返回值类型:malloc返回的时空指针类型,需要进行类型转换;new返回的是指定的类型,不需要进行类型转换
- 失败返回:malloc失败返回null类型;new失败会抛出异常
- 分配空间大小:malloc需要明确计算出大小,根据计算大小分配空间;new根据指定类型,可以自动分配
- malloc不可以重载,new可以重载,通过重载可以将
- malloc/free不会调用构造析构函数;new/delete会调用构造函数
c和c++
C主要是面向过程,针对事务发展的过程,进行编程;C++引入面向对象的思想,转向面向对象编程。通过对要实现问题的抽象总结,将其中的功能总结成模块。并通过继承、多态等特性,简化开发过程。
++i和i++哪个够快
++i返回的是来的i,i++返回的是i+1,有个临时变量,所以从逻辑上讲,前缀会更快一点。但是系统的实现其实没有多大的速度差别。和这个相关的还有一行中出现多个i++和++i的问题,因为从C/C++的编译器的实现逻辑上讲,只保证在这一行运行完,下一行开始运行之前,完成前缀和后缀运算,所以在一行中出现多个前缀和后缀的时候,可能结果并不是像预期的那样。对于在函数参数的中前缀和后缀运算,也需要注意,因为函数调用的时候,参数是从右向左入栈的,所以结果可能和预期的结果顺序不一样。
宏和内联函数
宏定义会在预编译的时候,在调用的位置直接替换,提高执行速度。
内联函数会在编译的时候,实现替换。内联函数不能有复杂的逻辑,不能有while、switch等语句。内联函数不可以调用自己。
区别:宏定义没有类型检查,可能会出错;内联函数是一个函数,只是少了调用的过程,有类型检查,更安全;
数组指针和指针数组
指针常量和常量指针
首先需要区分名字,哪个在前,形成的名字就是哪个在前(const就是常量);从功能上区分就是哪个在前,哪个就不能改,const在前,就是变量不能改,在前就是指针不能改;
int const * p;//const在前面,所以是常量指针;const所以指向的变量不能修改
int * const p;//*在前const在后,指针常量;*在前,所以指针不能改
对于c++的继承
继承主要实现重用代码,节省开发时间。
子类可以继承父类的一些东西。
a. 公有继承(public)
公有继承的特点是基类的公有成员和保护成员作为派生类的成员时,它们都保持原有的状态,而基类的私有成员仍然是私有的,不能被这个派生类的子类所访问。
b. 私有继承(private)
私有继承的特点是基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问。
c. 保护继承(protected)
保护继承的特点是基类的所有公有成员和保护成员都成为派生类的保护成员,并且只能被它的派生类成员函数或友元访问,基类的私有成员仍然是私有的。
c++公有、保护、私有访问控制
public:可以被该类中的函数、子类的函数、友元函数访问,也可以由该类的对象访问;
protected:可以被该类中的函数、子类的函数、友元函数访问,但不可以由该类的对象访问;
private:可以被该类中的函数、友元函数访问,但不可以由子类的函数、该类的对象、访问。
构造和析构的顺序
构造顺序:
父类构造函数->本类的构造函数->派生类构造函数;
析构顺序:
派生类的析构->本类的析构函数->父类的析构函数;
构造函数为什么不能是虚函数;析构函数为什么最好是虚函数
虚函数是存在对象后面的虚表中的,在没有调用对象的构造函数的时候,对象的存储空间还没有存在,所以没有使用虚函数。
在派生类中,往往是对父类对象特性的添加。即创建了新的变量,开辟了新的空间。所以需要在派生类中使用派生类的虚的析构函数释放空间。