面试准备-C++

C++面试

1.c++与c区别

2.union共同体和struct结构体的区别

3. static的作用

4.const的作用

5.指针和引用的区别

6. 重载、重写、隐藏的区别

7.虚函数与虚函数表相关知识点

8.C++中struct和class的区别

9数组指针和指针数组

10.strlen和sizeof的区别

11.进程和线程

12.C/C++内存有哪几种类型?

13.堆和栈的区别?

14.什么是内存泄漏?面对内存泄漏和指针越界,你有哪些方法?你通常采用哪些方法来避免和减少这类错误?

15. 函数调用的过程?

16. 左值和右值

18. 宏和内联(inline)函数的比较?

19.C++中有了malloc / free , 为什么还需要 new / delete?

20.强制类型转化

21.在C++程序中调用被C编译器编译后的函数,为什么要加extern“C”?

22.头文件中的 ifndef/define/endif 是干什么用的? 该用法和 program once 的区别?

23.说几个C++11的新特性

24. 32位,64位系统中,各种常用内置数据类型占用的字节数?

25.virtual, inline, decltype,volatile,static, const关键字的作用?使用场景?

26.深拷贝与浅拷贝的区别?

27.计算类大小例子

28.大端与小端的概念?各自的优势是什么?

29.C/C++中堆和栈的区别

30.指针常量与常量指针

31、函数模板与类模板有什么区别?

32.智能指针

1.c++与c区别

答:C 是面向过程的一门编程语言,C++ 可以很好地进行面向对象的程序设计,

C++ 对 C 的增强,表现在六个方面:

  • 增强了类型检查机制
  • 增加了面向对象的机制
  • 增加了泛型编程的机制(template)
  • 增加了异常处理
  • 增加了重载的机制
  • 增加了标准模板库

 参考:https://www.jianshu.com/p/2522b07219ae

2.union共同体和struct结构体的区别

  • struct和union都是由多个不同的数据类型成员组成
  • 同一时刻,union只存放了一个数据成员,而struct的所有成员都存在
  • 在struct中,每个成员都有自己的内存,它们同时存在,在union中,所有成员不能同时占用各自的一块内存,因此不能同时存在,只能存在一个
  • struct的长度为所有成员长度之和,union的长度为最长成员的长度
  • 对union不同成员赋值会重写其他成员,而struct的不同成员之间的赋值互不影响

3. static的作用

  • 修饰局部变量,改变了局部变量的存储区(栈->静态存储区)以及生命周期(离开作用于之后,并未被销毁,仍然驻留在内存,直到程序销毁,但是我们不能再对它进行访问),但未改变其作用域。
  • 修饰全局变量和函数,并未改变其存储位置及生命周期,而改变了其作用域,使当前文件外的源文件无法访问该变量和该函数。
  • 修饰类的成员变量,使其成为类的全局变量,被类的所有对象共享。
  • 修饰类的成员函数,所有对象共享该函数,函数属于类的,不需要创建对象即可访问;静态成员函数只能访问静态成员变量,不可访问非静态成员变量。

4.const的作用

  • 限定变量为不可修改
  • 限定成员函数不可以修改任何数据成员

5.指针和引用的区别

  • 指针是变量,存放变量的地址,占用4Byte或者8Byte,引用是别名,不占用内存空间
  • 指针可以为空,可以声明之后再初始化,引用必须在声明的时候初始化,而且初始化之后不可再改变
  • 指针可以有多级,引用不可以

6. 重载、重写、隐藏的区别

Overload(重载):在C++程序中,可以将语义、功能相似的几个函数用同一个名字表示,但是参数或者返回值不同

  • 相同的范围(同一个类中)
  • 函数名相同
  • 参数或者返回值不同
  • virtual关键字可有可无

Override(重写):派生类函数覆盖基类函数,用于多态

  • 不同的范围(分别位于基类和派生类)
  • 函数名相同
  • 参数和返回值相同
  • 必须有virtual关键字

Overwrite(隐藏),派生类函数屏蔽与其同名的基类函数规则如下

  • 派生类与基类函数同名,但是参数不同,基类函数将被隐藏
  • 派生类与基类函数同名,并且参数相同,但是基类函数没有virtual关键字,基类函数将被隐藏

7.虚函数与虚函数表相关知识点

多态是由虚函数实现的,而虚函数主要是通过虚函数表(V-Table)来实现的。

  • 类中若有virtual修饰的成员函数,该类就会有一个虚函数表
  • 该类定义的对象会有一个虚函数指针指向类的虚函数表,原始基类的对象的虚函数指针指向基类的虚函数表
  • 有纯虚函数的类为抽象类,不能被实例化。

8.C++中struct和class的区别

  • 默认继承权限
  • 成员的默认访问权限

  参考:https://blog.csdn.net/alidada_blog/article/details/83419757

9数组指针和指针数组

  • int (*ptr)[5],数组的指针相当于二维数组,也就是指针的指针
  • int *ptr[5],指针数组是一个数组,数组存放的元素为指针

10.strlen和sizeof的区别

  • strlen是函数,在运行时才能计算,返回字符串的长度,必须以‘\0’结尾;sizeof是运算符,在编译时就计算好了。

11.进程和线程

  • 进程是程序指令和相关资源的集合,是程序的运行实体,一个进程可以包含多个线程
  • 进程是资源分配的基本单位,线程是程序调度的基本单位,线程共享进程的资源(动态堆,静态存储区,代码段),但是具有自己独立的栈空间和寄存器
  • 进程的频繁切换需要包含进程资源的保护和恢复动作,因此会引起多额外的开销进而影响系统的性能,另外进程间的通信要求复杂的系统级实现,线程的切换比较快,容易实现并发,而且可以通过共享资源的方式进行多线程之间的通信,但是需要考虑同步的问题。

12.C/C++内存有哪几种类型?

C中,内存分为5个区:堆(malloc)、栈(如局部变量、函数参数)、程序代码区(存放二进制代 码)、全局/静态存储区(全局变量、static变量)和常量存储区(常量)。此外,C++中有自由存储区(new)一说。全局变量、static变量会初始化为零,而堆和栈上的变量是随机的,不确定的。

13.堆和栈的区别?

1).堆存放动态分配的对象——即那些在程序运行时分配的对象,比如局部变量,其生存期由程序控制;

2).栈用来保存定义在函数内的非static对象,仅在其定义的程序块运行时才存在;

3).静态内存用来保存static对象,类static数据成员以及定义在任何函数外部的变量,static对象在使用之前分配,程序结束时销毁;

4).栈和静态内存的对象由编译器自动创建和销毁。

14.什么是内存泄漏?面对内存泄漏和指针越界,你有哪些方法?你通常采用哪些方法来避免和减少这类错误?

用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元即为内存泄露。

1). 使用的时候要记得指针的长度.

2). malloc的时候得确定在那里free.

3). 对指针赋值的时候应该注意被赋值指针需要不需要释放.

4). 动态分配内存的指针最好不要再次赋值.

5). 在C++中应该优先考虑使用智能指针.

15. 函数调用的过程?

int main(void) { ... d = fun(a, b, c); cout<<d<<endl; ... return 0; }

调用fun()的过程大致如下:

main()========

1).参数拷贝(压栈),注意顺序是从右到左,即c-b-a;

2).保存d = fun(a, b, c)的下一条指令,即cout<<d<<endl(实际上是这条语句对应的汇编指令的起始位置);

3).跳转到fun()函数,注意,到目前为止,这些都是在main()中进行的;

fun()=====

4).移动ebp、esp形成新的栈帧结构;

5).压栈(push)形成临时变量并执行相关操作;

6).return一个值;

7).出栈(pop);

8).恢复main函数的栈帧结构;

9).返回main函数;

main()========

16. 左值和右值

https://blog.csdn.net/Tanswer_/article/details/77005674?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-3&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-3

17. int fun() 和 int fun(void)的区别?

这里考察的是c 中的默认类型机制。

在c中,int fun() 会解读为返回值为int(即使前面没有int,也是如此,但是在c++中如果没有返回类型将报错),输入类型和个数没有限制, 而int fun(void)则限制输入类型为一个void。

在c++下,这两种情况都会解读为返回int类型,输入void类型。

18. 宏和内联(inline)函数的比较?

1). 首先宏是C中引入的一种预处理功能;

2). 内联(inline)函数是C++中引用的一个新的关键字;C++中推荐使用内联函数来替代宏代码片段;

3). 内联函数将函数体直接扩展到调用内联函数的地方,这样减少了参数压栈,跳转,返回等过程;

4). 由于内联发生在编译阶段,所以内联相较宏,是有参数检查和返回值检查的,因此使用起来更为安全;

5). 需要注意的是, inline会向编译期提出内联请求,但是是否内联由编译期决定(当然可以通过设置编译器,强制使用内联);

6). 由于内联是一种优化方式,在某些情况下,即使没有显示的声明内联,比如定义在class内部的方法,编译器也可能将其作为内联函数。

7). 内联函数不能过于复杂,最初C++限定不能有任何形式的循环,不能有过多的条件判断,不能对函数进行取地址操作等,但是现在的编译器几乎没有什么限制,基本都可以实现内联。

19.C++中有了malloc / free , 为什么还需要 new / delete?

1). malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。

2). 对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。

由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。

最后补充一点体外话,new 在申请内存的时候就可以初始化(如下代码), 而malloc是不允许的。另外,由于malloc是库函数,需要相应的库支持,因此某些简易的平台可能不支持,但是new就没有这个问题了,因为new是C++语言所自带的运算符。

补充:

  • new是运算符,malloc()是一个库函数;
  • new会调用构造函数,malloc不会;
  • new返回指定类型指针,malloc返回void*指针,需要强制类型转换;
  • new会自动计算需分配的空间,malloc不行;
  • new可以被重载,malloc不能。

20.强制类型转化

1).static_cast

a. 用于基本类型间的转换

b. 不能用于基本类型指针间的转换

c. 用于有继承关系类对象间的转换和类指针间的转换

2). dynamic_cast

a. 用于有继承关系的类指针间的转换

b. 用于有交叉关系的类指针间的转换

c. 具有类型检查的功能

d. 需要虚函数的支持

3). reinterpret_cast

a. 用于指针间的类型转换

b. 用于整数和指针间的类型转换

4). const_cast

a. 用于去掉变量的const属性

b. 转换的目标类型必须是指针或者引用

21.在C++程序中调用被C编译器编译后的函数,为什么要加extern“C”?

C++语言支持函数重载,C语言不支持函数重载,函数被C++编译器编译后在库中的名字与C语言的不同,假设某个函数原型为:

void foo(int x, int y);

1

该函数被C编译器编译后在库中的名字为 _foo, 而C++编译器则会产生像: _foo_int_int 之类的名字。为了解决此类名字匹配的问题,C++提供了C链接交换指定符号 extern “C”。

22.头文件中的 ifndef/define/endif 是干什么用的? 该用法和 program once 的区别?

相同点:

它们的作用是防止头文件被重复包含。

不同点

1). ifndef 由语言本身提供支持,但是 program once 一般由编译器提供支持,也就是说,有可能出现编译器不支持的情况(主要是比较老的编译器)。

2). 通常运行速度上 ifndef 一般慢于 program once,特别是在大型项目上, 区别会比较明显,所以越来越多的编译器开始支持 program once。

3). ifndef 作用于某一段被包含(define 和 endif 之间)的代码, 而 program once 则是针对包含该语句的文件, 这也是为什么 program once 速度更快的原因。

4). 如果用 ifndef 包含某一段宏定义,当这个宏名字出现“撞车”时,可能会出现这个宏在程序中提示宏未定义的情况(在编写大型程序时特性需要注意,因为有很多程序员在同时写代码)。相反由于program once 针对整个文件, 因此它不存在宏名字“撞车”的情况, 但是如果某个头文件被多次拷贝,program once 无法保证不被多次包含,因为program once 是从物理上判断是不是同一个头文件,而不是从内容上。

23.说几个C++11的新特性

24. 32位,64位系统中,各种常用内置数据类型占用的字节数?

char :1个字节(固定)

*(即指针变量): 4个字节(32位机的寻址空间是4个字节。同理64位编译器)(变化*)

short int : 2个字节(固定)

int: 4个字节(固定)

unsigned int : 4个字节(固定)

float: 4个字节(固定)

double: 8个字节(固定)

long: 4个字节

unsigned long: 4个字节(变化*,其实就是寻址控件的地址长度数值)

long long: 8个字节(固定)

64位操作系统

char :1个字节(固定)

*(即指针变量): 8个字节

short int : 2个字节(固定)

int: 4个字节(固定)

unsigned int : 4个字节(固定)

float: 4个字节(固定)

double: 8个字节(固定)

long: 8个字节

unsigned long: 8个字节(变化*其实就是寻址控件的地址长度数值)

long long: 8个字节(固定)

除*与long 不同其余均相同。

25.virtual, inline, decltype,volatile,static, const关键字的作用?使用场景?

inline:在c/c++中,为了解决一些频繁调用的小函数大量消耗栈空间(栈内存)的问题,特别的引入了inline修饰符,表示为内联函数。

decltype:从表达式中推断出要定义变量的类型,但却不想用表达式的值去初始化变量。还有可能是函数的返回类型为某表达式的的值类型。

volatile:volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。

static:

  1. 隐藏

      在变量和函数名前面如果未加static,则它们是全局可见的。加了static,就会对其它源文件隐藏,利用这一特性可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲  突。static可以用作函数和变量的前缀,对于函数来讲,static的作用仅限于隐藏 。

    2.static变量中的记忆功能和全局生存期

26.深拷贝与浅拷贝的区别?

1.什么时候用到拷贝函数?

  a.一个对象以值传递的方式传入函数体; 

  b.一个对象以值传递的方式从函数返回;

  c.一个对象需要通过另外一个对象进行初始化。

  如果在类中没有显式地声明一个拷贝构造函数,那么,编译器将会自动生成一个默认的拷贝构造函数,该构造函数完成对象之间的位拷贝。位拷贝又称浅拷贝;

2.是否应该自定义拷贝函数?

 自定义拷贝构造函数是一种良好的编程风格,它可以阻止编译器形成默认的拷贝构造函数,提高源码效率。

3.什么叫深拷贝?什么是浅拷贝?两者异同?

  如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝。

4.深拷贝好还是浅拷贝好?

如果实行位拷贝,也就是把对象里的值完全复制给另一个对象,如A=B。这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。这就出现了问题:当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。

27.计算类大小例子

class A {};: sizeof(A) = 1;

class A { virtual Fun(){} };: sizeof(A) = 4(32位机器)/8(64位机器);

class A { static int a; };: sizeof(A) = 1;

class A { int a; };: sizeof(A) = 4;

class A { static int a; int b; };: sizeof(A) = 4;

28.大端与小端的概念?各自的优势是什么?

  • 大端与小端是用来描述多字节数据在内存中的存放顺序,即字节序。大端(Big Endian)指低地址端存放高位字节,小端(Little Endian)是指低地址端存放低位字节。
  • 需要记住计算机是以字节为存储单位。
  • 为了方便记忆可把大端和小端称作高尾端和低尾端,eg:如果是高尾端模式一个字符串“11223344”把尾部“44”放在地址的高位,如果是地尾端模式,把“44”放在地址的低位。

各自优势:

  • Big Endian:符号位的判定固定为第一个字节,容易判断正负。
  • Little Endian:长度为1,2,4字节的数,排列方式都是一样的,数据类型转换非常方便。

举一个例子,比如数字0x12 34 56 78在内存中的表示形式为:

  • 1)大端模式:

低地址 -----------------> 高地址

0x12 | 0x34 | 0x56 | 0x78

  • 2)小端模式:

低地址 ------------------> 高地址

0x78 | 0x56 | 0x34 | 0x12

29.C/C++中堆和栈的区别

讲解全面的一篇博客:https://blog.csdn.net/Fiorna0314/article/details/49757195

链接1

链接2

30.指针常量与常量指针

常量指针(被指向的对象是常量)

定义:又叫常指针,可以理解为常量的指针,指向的是个常量

关键点:

  1. 常量指针指向的对象不能通过这个指针来修改,可是仍然可以通过原来的声明修改;
  2. 常量指针可以被赋值为变量的地址,之所以叫常量指针,是限制了通过这个指针修改变量的值;
  3. 指针还可以指向别处,因为指针本身只是个变量,可以指向任意地址;

const int *p或int const *p

(记忆技巧:const读作常量,*读作指针)

#include <stdio.h> // 常量指针(被指向的对象是常量) int main() { int i = 10; int i2 = 11; const int *p = &i; printf("%d\n", *p);//10 i = 9; //OK,仍然可以通过原来的声明修改值, //Error,*p是const int的,不可修改,即常量指针不可修改其指向地址 //*p = 11; //error: assignment of read-only location ‘*p’ p = &i2;//OK,指针还可以指向别处,因为指针只是个变量,可以随意指向; printf("%d\n", *p);//11 return 0; }

指针常量(指针本身是常量)

定义:

本质是一个常量,而用指针修饰它。指针常量的值是指针,这个值因为是常量,所以不能被赋值。

关键点:

  1. 它是个常量!
  2. 指针所保存的地址可以改变,然而指针所指向的值却不可以改变;
  3. 指针本身是常量,指向的地址不可以变化,但是指向的地址所对应的内容可以变化;

int* const p;

//指针常量(指针本身是常量) #include <stdio.h> int main() { int i = 10; int *const p = &i; printf("%d\n", *p);//10 //Error,因为p是const 指针,因此不能改变p指向的内容 //p++;//error: increment of read-only variable ‘p’ (*p)++; //OK,指针是常量,指向的地址不可以变化,但是指向的地址所对应的内容可以变化 printf("%d\n", *p);//11 i = 9;//OK,仍然可以通过原来的声明修改值, return 0; }

31、函数模板与类模板有什么区别?

【参考答案】

函数模板的实例化是由编译程序在处理函数调用时自动完成的,而类模板的实例化必须由程序员在程序中显式地指定。

32.智能指针

shared_ptr unique_ptr,weak_ptr,auto_ptr

https://blog.csdn.net/flowing_wind/article/details/81301001

https://blog.csdn.net/k346k346/article/details/81478223#1unique_ptr_4

参考:

https://blog.csdn.net/kuweicai/article/details/82779648

https://zhuanlan.zhihu.com/p/51918989

猜你喜欢

转载自blog.csdn.net/weixin_39752599/article/details/105943786