文章目录
-
-
- C++基础
- 构造函数为什么不能定义为虚函数,析构函数为什么可以?
- 基类的有1个虚函数,子类还需要申明为virtual吗?为什么。
-
- 纯虚函数的作用和实现方式
- 虚函数是怎么实现的
- 你刚刚提到虚函数表,具体是怎样实现运行时多态的。
- 哪些函数不能是虚函数?
- C++内存模型是什么?如何理解自由存储区与堆的区别?
- 为什么在C++里面,一个类的成员函数不能既是 template 又是 virtual 的
- 静态多态和动态多态
- 使用过模板么?了解哪些特性?(提问概率:★★★★)
- 有哪些内存泄漏?如何判断内存泄漏?如何定位内存泄漏?
- c++ 空类,含有虚函数的类的大小
- 字节对齐的原则
- STL源码、vector、list、map、set
- 静态连接与动态链接的区别
- 什么是面向对象(OOP)?和多态?举一个多态的例子
- 重写、重载与隐藏的区别
- 必须在构造函数初始化式里进行初始化的数据成员有哪些
- C++ 类内可以定义引用数据成员吗?
- 什么情况下会调用拷贝构造函数(三种情况)
- C++的类对象为什么不能用memset初始化?
- C++四种类型转换
- 如何实现一个引用计数指针,以及其中要注意的点?
- 如何让一个类不能实例化?
- 如何让main函数之前执行函数?
- C++如何创建一个类,使得他只能在堆或者栈上创建?
- 引用传递、值传递、指针传递
- explict关键字的作用
- C++内存管理
- 定位内存泄露
- GDB调试
- 指针常量和常量指针
- 编译相关
- STL库相关
- C++11新特性部分
- C++14新特性部分
- c++ 性能调优
-
C++软件工程师主要必备有C++基础(最好也懂Java)、数据结构及简单算法、TCP、操作系统、网络编程、Linux基本操作和Shell编程、数据库,设计模式等。
C++基础
参考资料:《Effective C++》、《C++ Prime》、《STL源码剖析》
《c++基础》
C和C++的区别?
C是面向过程的语言,C++是面向对象的语言
C++中new和delete是对内存分配的运算符,取代了C中的malloc和free的库函数
C++中有引用的概念,C中没有
C++引入了类的概念,C中没有
C++有函数重载,C中不能
C变量只能在函数的开头处声明和定义,而C++随时定义随时使用
C++和Java之间的区别?
Java的应用在高层,C++在中间件和底层
Java语言简洁;取消了指针带来更高的代码质量;完全面向对象,独特的运行机制是其具有天然的可移植性。
Java在web应用上具有C++无可比拟的优势
垃圾回收机制的区别。C++ 用析构函数回收垃圾,Java自动回收,写C和C++程序时一定要注意内存的申请和释放。
Java用接口(Interface)技术取代C++程序中的多继承性
什么是面向对象?面向对象的几大特性是什么?
面向对象是一种基于对象的、基于类的的软件开发思想。面向对象具有继承、封装、多态的特性。
指针和引用的区别
- 指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元;而引用仅是个别名;
- 引用使用时无需解引用(*),指针需要解引用;
- 引用只能在定义时被初始化一次,之后不可变;指针可变;
- 引用没有 const,指针有 const;
- 引用不能为空,指针可以为空;
- “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身的大小;
- 指针和引用的自增(++)运算意义不一样;
- 指针可以有多级,但是引用只能是一级(int **p;合法 而 int &&a是不合法的)
9.从内存分配上看:程序为指针变量分配内存区域,而引用不需要分配内存区域。
new/delete和malloc/free的区别
-
malloc和free是库函数,而new和delete是C++操作符;
-
new自己计算需要的空间大小,比如’int * a = new,malloc需要指定大小,例如’int * a = malloc(sizeof(int))’;
-
new在动态分配内存的时候可以初始化对象,调用其构造函数,delete在释放内存时调用对象的析构函数。而malloc只分配一段给定大小的内存,并返回该内存首地址指针,如果失败,返回NULL。
-
new是C++操作符,是关键字,而operate new是C++库函数
-
opeartor new /operator delete可以重载,而malloc不行
-
new可以调用malloc来实现,但是malloc不能调用new来实现
-
对于数据C++定义new[]专门进行动态数组分配,用delete[]进行销毁。new[]会一次分配内存,然后多次调用构造函数;delete[]会先多次调用析构函数,然后一次性释放。
分配数组不同之处
int char* pa = new char[100];
int char* pb = malloc(sizeof(char) * 100);
8. malloc能够直观地重新分配内存
使用malloc分配的内存后,如果在使用过程中发现内存不足,可以使用realloc函数进行内存重新分配实现内存的扩充。realloc先判断当前的指针所指内存是否有足够的连续空间,如果有,原地扩大可分配的内存地址,并且返回原来的地址指针;如果空间不够,先按照新指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来的内存区域。
new没有这样直观的配套设施来扩充内存。
volatile关键字是干啥的
1.访问寄存器要比访问内存要块,因此CPU会优先访问该数据在寄存器中的存储结果,但是内存中的数据可能已经发生了改变,而寄存器中还保留着原来的结果。为了避免这种情况的发生将该变量声明为volatile,告诉CPU每次都从内存去读取数据。
2.一个参数可以即是const又是volatile的吗?可以,一个例子是只读状态寄存器,是volatile是因为它可能被意想不到的被改变,是const告诉程序不应该试图去修改他。
static关键字的作用
《C/C++ 中 static 的用法》
static修饰全局函数有什么作用?
限制他的作用域只能在本文件之内。
extern关键字作用
在C++ 程序中调用被 C 编译器编译后的函数,为什么要加 extern “C”声明?
函数和变量被C++编译后在符号库中的名字与C语言的不同,被extern “C”修饰的变量和函数是按照C语言方式编译和连接的。由于编译后的名字不同,C++程序不能直接调用C 函数。C++提供了一个C 连接交换指定符号extern“C”来解决这个问题。
extern声明变量在在外部定义?
extern是作变量声明,而不是变量定义。它只是对一个已经定义的外部变量作声明,以扩展其作用域。
extern修饰函数?
如果函数的声明中带有关键字extern,仅仅是暗示这个函数可能在别的源文件里定义,没有其它作用。
const关键字的作用
define/const/inline的区别
本质:define只是字符串替换,const参与编译运行,具体的:
define不会做类型检查,const拥有类型,会执行相应的类型检查
. define仅仅是宏替换,不占用内存,而const会占用内存
const内存效率更高,编译器通常将const变量保存在符号表中,而不会分配存储空间,这使得它成为一个编译期间的常量,没有存储和读取的操作
本质:define只是字符串替换,inline由编译器控制,具体的:
内联函数在编译时展开,而宏是由预处理器对宏进行展开
内联函数会检查参数类型,宏定义不检查函数参数 ,所以内联函数更安全。
宏不是函数,而inline函数是函数
宏在定义时要小心处理宏参数,(一般情况是把参数用括弧括起来)。
C++构造函数能抛异常吗?析构呢?
构造函数可以抛出异常。 C++标准指明析构函数不能、也不应该抛出异常。
1)如果析构函数抛出异常,则异常点之后的程序不会执行,如果析构函数在异常点之后执行了某些必要的动作比如释放某些资源,则这些动作不会执行,会造成诸如资源泄漏的问题。
2)通常异常发生时,c++的机制会调用已经构造对象的析构函数来释放资源,此时若析构函数本身也抛出异常,则前一个异常尚未处理,又有新的异常,会造成程序崩溃的问题。
C++/C内存分配方式,堆与栈的区别
一、堆栈空间分配区别:
1、栈(操作系统):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈;
2、堆(操作系统): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。
二、堆栈缓存方式区别:
1、栈使用的是一级缓存, 他们通常都是被调用时处于存储空间中,调用完毕立即释放;
2、堆是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些。
三、堆栈数据结构区别:
堆(数据结构):堆可以被看成是一棵树,如:堆排序;
栈(数据结构):一种先进后出的数据结构。
《C++/C内存分配方式,堆与栈的区别》
构造函数为什么不能定义为虚函数,析构函数为什么可以?
虚函数的执行依赖于虚函数表。而虚函数表需要在构造函数中进行初始化工作,即初始化vptr,让他指向正确的虚函数表。而在构造对象期间,虚函数表还没有被初始化,将无法进行。
在类的继承中,如果有基类指针指向派生类,那么用基类指针delete时,如果不定义成虚函数,派生类中派生的那部分无法析构。
构造函数不要调用虚函数。在基类构造的时候,虚函数是非虚,不会走到派生类中,既是采用的静态绑定。显然的是:当我们构造一个子类的对象时,先调用基类的构造函数,构造子类中基类部分,子类还没有构造,还没有初始化,如果在基类的构造中调用虚函数,如果可以的话就是调用一个还没有被初始化的对象,那是很危险的,所以C++中是不可以在构造父类对象部分的时候调用子类的虚函数实现。但是不是说你不可以那么写程序,你这么写,编译器也不会报错。只是你如果这么写的话编译器不会给你调用子类的实现,而是还是调用基类的实现。
基类的有1个虚函数,子类还需要申明为virtual吗?为什么。
不申明也没有关系,但我一般会显示的声明,并使用override,避免因为因为参数 不同而没有覆盖基类虚函数
纯虚函数的作用和实现方式
(1)作用:定义纯虚函数是为了实现一个接口,起到一个规范的作用,规范继承这个类的程序员必须实现这个函数。
应该在什么情况下使用