c++高频面试题

指针和引用的区别?

1、引用必须初始化,指针可以不初始化,建议初始化。

2、指针和引用的自增(++)运算意义不一样;

3、引用是变量的别名,指针指向的是地址。

4、指针可以使用const,引用没有const。

5、指针可以有多级,引用只能是一级。

6、指针的值可以改变,引用的值不可以改变。

7、sizeof引用是对象的大小,sizeof指针是指针的大小。


堆和栈的区别?

1、分配方式,栈编译器分配,堆程序员手动分配;

2、栈切换开销小,堆切换开销大;

3、增长方向不同,堆的生长方向向上,内存地址由低到高;栈的生长方向向下,内存地址由高到低;

4、分配大小,栈很小,1M,堆很大。

5、栈不会产生碎片,堆会产生碎片。

6、存放内容不同。栈存放的内容,函数返回地址、相关参数、局部变量和寄存器内容等。堆,一般情况堆顶使用一个字节的空间来存放堆的大小,而堆中具体存放内容是由程序员来填充的。


new和delete是如何实现的,new 与 malloc的异同处?

1、new在底层调用operator new全局函数来申请空间;

2、delete在底层通过operator delete全局函数来释放空间;

3、operator new 实际是通过malloc来申请空间的,

4、operator delete实际是通过free来释放空间的;

内置类型:

如果申请的是内置类型的空间,new和malloc,delete和free基本类似;

不同之处:

new在申请空间失败时会抛异常;

malloc在申请空间失败时会返回NULL;

自定义类型:

new的原理:

调用operator new函数申请空间;

在申请的空间上执行构造函数,完成对象的构造;

delete的原理:

在空间上执行析构函数,完成对象中资源的清理工作;

调用operator delete函数释放对象的空间;

new[N]的原理:

调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请;

在申请的空间上执行N次构造函数;

delete[N]的原理:

在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理;

调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间;

1、new是关键字,malloc是函数;

2、使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算,而malloc则需要显式地指出所需内存的尺寸。

3、new调用构造函数,malloc不会;

4、new操作符从自由存储区(free store)上为对象动态分配内存空间,而malloc函数从上动态分配内存。

5、new操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换,故new是符合类型安全性的操作符。而malloc内存分配成功则是返回void * ,需要通过强制类型转换将void*指针转换成我们需要的类型。

6、new内存分配失败时,会抛出bac_alloc异常,它不会返回NULL;malloc分配内存失败时返回NULL。

7、new可以重载,malloc不可以重载


7898366-9927723edfae8780.png

C和C++的区别?

1、C是面向过程的,C++是面向对象的;

2、C语言不支持函数默认值,C++支持函数默认值,且需要遵循从右向左赋初始值。

3、c没有内敛函数,c++有内敛函数

4、c函数不可以重载,c++函数可以重载

5、C中的const叫只读变量,只是无法做左值的变量;C++中的const是真正的常量,但也有可能退化成c语言的常量,默认生成local符号。

6、c++有引用,c没有

7、C语言中作用域只有两个:局部,全局。C++中则是有:局部作用域,类作用域,名字空间作用域三种。


C++、Java的联系与区别,包括语言特性、垃圾回收、应用场景等(java的垃圾回收机制)?


Struct和class的区别?

1、struct默认访问权限public,class默认访问权限private

2、“class”这个关键字还用于定义模板参数,就像“typename”。但关键字“struct”不用于定义模板参数

C++保留struct关键字,原因:

保证与C语言的向下兼容性,C++必须提供一个struct

C++中的struct定义必须百分百地保证与C语言中的struct的向下兼容性,把C++中的最基本的对象单元规定为class而不是struct,就是为了避免各种兼容性要求的限制

对struct定义的扩展使C语言的代码能够更容易的被移植到C++中


define 和const的区别(编译阶段、安全性、内存占用等)?

1、类型与安全检查不同:define – 无类型,不进行类型安全检查,可能会产生意想不到的错误(边际效应);const – 有数据类型,编译时会进行类型检查

2、编译器处理方式不同:define – 在预处理阶段进行替换;const – 在编译时确定其值

3、用define可以定义一些简单的函数,const是不可以定义函数的.

4、用define定义的常量是不可以用指针变量去指向的,用const定义的常量是可以用指针去指向该常量的地址的。

5、存储方式不同:define – 不分配内存,给出的是立即数,有多少次使用就进行多少次替换,在内存中会有多个拷贝,消耗内存大;const – 在静态存储区中分配空间,在程序运行过程中内存中只有一个拷贝,const可以节省空间,避免不必要的的内存分配。


在C++中const和static的用法(定义,用途)?

函数(static 里面不包含this指针)

a.静态函数只能访问静态成员变量(不需要this指针)

b.静态函数不能访问普通成员函数,反之成立(静态成员函数没有this指针)

2. 存储方式-------------->共有的(它的值会被保存,下次调用仍保持上一次数值)

a.局部变量 : 在该函数执行变量结束后,该变量不会被释放,继续保存

b.全局变量 : 表示当变量在全局内都可以访问

c.类成员变量 : 表示这个变量为全类所有的(所有对象都公用这个变量,它不是某一个对象的私有的)

const的使用 (只具有读的工能)

const 常量:定义时就初始化,以后不能更改。

const 形参:func(const int a){};该形参在函数里不能改变

const修饰类成员函数:该函数对成员变量只能进行只读操作

可以作为重载函数  void  func(Test  * const this(默认的)) const ---------=>void  func(const  Test * const this):这个函数只具有读的功能,不能对对其变量进行修改;因为this指针为常量,不能变化,它和static成员函数类似,普通函数可以访问常成员函数,反之则不成立.常成员函数只能访问常成员变量

static : 为静态变量,只和类有关系,和对象无关,即使没有对象也可以调用静态函数和变量.

数据类型 类名::静态数据成员名=值    int Test::a = 10;

const : 初始化必须有构造函数初始化,不同对象const的数值不一样.


const和static在类中使用的注意事项(定义、初始化和使用)


C++中的const类成员函数(用法和意义),以及和非const成员函数的区别


C++的顶层const和底层const?

底层const是代表对象本身是一个常量(不可改变);

顶层const是代表指针的值是一个常量,而指针的值(即对象的地址)的内容可以改变(指向的不可改变);


final和override关键字?

要确认派生类中的成员函数覆盖基类中的虚成员函数,可以在派生类的函数原型(如果函数以内联方式写入,则在函数头)后面加上 override 关键字。override 关键字告诉编译器,该函数应覆盖基类中的函数。如果该函数实际上没有覆盖任何函数,则会导致编译器错误。

override的作用就出来了,它指定了子类的这个虚函数是重写的父类的,如果你名字不小心打错了的话,编译器是不会编译通过的。

override修饰的函数表示这个函数一定是父类(祖先)中传下来的,这样就帮助我们进行了函数的名称、参数的检查。

当不希望某个类被继承,或不希望某个虚函数被重写,可以在类名和虚函数后添加final关键字,添加final关键字后被继承或重写,编译器会报错。

c++中的final关键字是用来修饰一个函数,防止这个函数被子类重写。


拷贝初始化和直接初始化,初始化和赋值的区别?

初始化的复制形式和直接形式有所不同:直接初始化直接调用与实参匹配的构造函数,复制初始化总是调用复制构造函数。复制初始化首先使用指定构造函数创建一个临时对象,然后用复制构造函数将那个临时对象复制到正在创建的对象。

初始化与赋值是不同的概念:静态变量的初始化是在编译时进行,变量的赋值是在函数或程序运行时进行。静态变量只初始化一次,但可以通过赋值的方式多次修改静态变量的值。


extern "C"的用法?

1. extern "C"功能:为了能够正确的在C++代码中调用C语言的代码;

在程序中加上extern "C"后,相当于告诉编译器这部分代码是C语言写的,因此要按照C语言进行编译,而不是C++;

2. 哪些情况下使用extern "C":

(1)C++代码中调用C语言代码;

(2)在C++中的头文件中使用;

(3)在多个人协同开发时,可能有人擅长C语言,而有人擅长C++;

3. C++语言允许函数重载;但C语言是一门单一名字空间的语言,不允许函数重载;

为了能在C++程序里调用C语言程序,C++引入了链接规范,格式:extern "language string";


7898366-591236c7ba9cf2ab.png

模板函数和模板类的特例化


C++的STL源码(这个系列也很重要,建议侯捷老师的STL源码剖析书籍与视频),其中包括内存池机制,各种容器的底层实现机制,算法的实现原理等)


STL源码中的hashtable的实现?


STL中unordered_map和map的区别和应用场景?


STL中vector的实现?


STL容器的几种迭代器以及对应的容器(输入迭代器,输出迭代器,前向迭代器,双向迭代器,随机访问迭代器)

顺序容器:vector,deque是随机访问迭代器;list是双向迭代器

容器适配器:stack,queue,priority_queue没有迭代器

关联容器:set,map,multiset,multimap是双向迭代器

unordered_set,unordered_map,unordered_multiset,unordered_multimap是前向迭代器


STL中的traits技法

type_traits

iterator_traits

char traits

allocator_traits

pointer_traits

array_traits


vector使用的注意点及其原因,频繁对vector调用push_back()对性能的影响和原因。


C++中的重载和重写的区别


C++内存管理,内存池技术(热门问题),与csapp中几种内存分配方式对比学习加深理解


介绍面向对象的三大特性,并且举例说明每一个


C++多态的实现


C++虚函数相关(虚函数表,虚函数指针),虚函数的实现原理(包括单一继承,多重继承等)(拓展问题:为什么基类指针指向派生类对象时可以调用派生类成员函数,基类的虚函数存放在内存的什么区,虚函数表指针vptr的初始化时间)


C++中类的数据成员和成员函数内存分布情况

首先介绍一下C++中有继承关系的类对象内存的布局: 

在C++中,如果类中有虚函数,那么它就会有一个虚函数表的指针__vfptr,在类对象最开始的内存数据中。之后是类中的成员变量的内存数据。 

对于子类,最开始的内存数据记录着父类对象的拷贝(包括父类虚函数表指针和成员变量)。 之后是子类自己的成员变量数据。 

对于子类的子类,也是同样的原理。但是无论继承了多少个子类,对象中始终只有一个虚函数表指针。 


this指针

每一个对象都能通过 this 指针来访问自己的地址。this 指针是所有成员函数的隐含参数。因此,在成员函数内部,它可以用来指向调用对象。

友元函数没有 this 指针,因为友元不是类的成员。只有成员函数才有 this 指针。

this 是 const 指针,它的值是不能被修改的,一切企图修改该指针的操作,如赋值、递增、递减等都是不允许的。

this 只能在成员函数内部使用,用在其他地方没有意义,也是非法的。

只有当对象被创建后 this 才有意义,因此不能在 static 成员函数中使用)。


析构函数一般写成虚函数的原因


构造函数、拷贝构造函数和赋值操作符的区别


构造函数:对象不存在,没用别的对象初始化


拷贝构造函数:对象不存在,用别的对象初始化


赋值运算符:对象存在,用别的对象给它赋值


构造函数声明为explicit

      explicit关键字只需用于类内的单参数构造函数前面。由于无参数的构造函数和多参数的构造函数总是显示调用,这种情况在构造函数前加explicit无意义。


构造函数为什么一般不定义为虚函数?

从C++之父Bjarne的回答我们应该知道C++为什么不支持构造函数是虚函数了,简单讲就是没有意义。虚函数的作用在于通过子类的指针或引用来调用父类的那个成员函数。而构造函数是在创建对象时自己主动调用的,不可能通过子类的指针或者引用去调用。


构造函数的几种关键字(default delete 0)

= default:将拷贝控制成员定义为=default显式要求编译器生成合成的版本

= delete:将拷贝构造函数和拷贝赋值运算符定义删除的函数,阻止拷贝(析构函数不能是删除的函数 C++Primer P450)

= 0:将虚函数定义为纯虚函数(纯虚函数无需定义,= 0只能出现在类内部虚函数的声明语句处;当然,也可以为纯虚函数提供定义,不过函数体必须定义在类的外部)


构造函数或者析构函数中调用虚函数会怎样?


纯虚函数


静态类型和动态类型,静态绑定和动态绑定的介绍

引用是否能实现动态绑定,为什么引用可以实现

深拷贝和浅拷贝的区别(举例说明深拷贝的安全性)

对象复用的了解,零拷贝的了解

介绍C++所有的构造函数

什么情况下会调用拷贝构造函数(三种情况)

结构体内存对齐方式和为什么要进行内存对齐?

内存泄露的定义,如何检测与避免?

手写智能指针的实现(shared_ptr和weak_ptr实现的区别)

智能指针的循环引用

遇到coredump要怎么调试

内存检查工具的了解valgrind


模板的用法与适用场景

成员初始化列表的概念,为什么用成员初始化列表会快一些(性能优势)?

用过C++ 11吗,知道C++ 11哪些新特性?

C++的调用惯例(简单一点C++函数调用的压栈过程)

C++的四种强制转换

static_cast

dynamic_cast

const_cast

reinterpret_cast

C++中将临时变量作为返回值的时候的处理过程(栈上的内存分配、拷贝过程)

C++的异常处理

volatile关键字

优化程序的几种方法

public,protected和private访问权限和继承

class和struct的区别

decltype()和auto

inline和宏定义的区别

C++和C的类型安全

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值