【C++】软件开发面试常见问题

1. 请谈谈对多态的理解?
1)同样的调用语句有多种不同的表现形式;同一函数在不同父类子类中穿梭 表现为不同的形态
2)必要条件:有继承、virtual重写、指向子类对象的父类指针(引用)
3)设计模式的基础,是框架的基石

2. C++编译器是如何实现多态?
1)动态联编原理,通过添加关键字virtual,就告诉编译器这个函数要支持多态,不是根据指针类型判断来如何调用,而是要根据指针 实际所指向对象类型来判断如何调用。动态联编是指程序联编推迟到运行时进行,区别于“静态联编

3. 谈谈对重写,重载以及重定义理解?
1)函数重写:发生于父类与子类间;父类与子类函数原型相同;使用virtual能产生多态(若不添加virtual就是“重定义”)
2)函数重载:发生于同一类;子类无法重载父类的函数,父类同名函数会被覆盖

4. 是否类的每个成员函数都能声明为虚函数?
1)可以,不推荐;应为是动态编译,影响程序效率

5.为什么要定义虚析构函数?
1)存在多对象时,单独对每个对象析构效率慢且易发生内存泄漏;则可通过给父类定义虚析构函数virtual ~A(),实现所有资源释放(包括子类)
2)构造函数不能是虚函数,构造函数中调用虚函数也不会发生多态;从语法上讲,调用完全没有问题。但是从效果看,不能达到需要的目的。
https://blog.csdn.net/donotgogentle/article/details/107222597

6. 谈谈函数传值的方式以及它们间的区别?
1)值传递、指针传递(地址传递)、引用传递(变量本身,即地址和值)
2)值传递:可读性高、安全稳定;传递过程中效率低且浪费空间,不能以形参改变实参
2)指针传递:可读性低,不安全;效率高且节省空间,能通过形参改变实参
3)引用传递:安全、实用且可读性好;传递过程不产生副本、高效;直接操作对象;适用于函数传参以及大数据块或对象传递

7. 智能指针有哪些以及作用?
1)智能指针是利用了一种叫做RAII(资源获取即初始化)的技术对普通的指针进行封装,这使得智能指针实质是个对象,行为像一个指针
2)智能指针的作用是防止忘记调用delete释放内存和程序异常的进入catch块忘记释放内存以及很好解决内存释放时机问题
3)auto_ptr: 现在版本多已不用;auto_ptr还是足够智能的,但是它还是有一些根本性的破绽的,如不能和操作符new[]一起使用
4)shared_ptr:多个指针可以同时指向一个对象,当最后一个shared_ptr离开作用域时,内存才会自动释放(建议存在拷贝赋值时用)
5)weak_ptr: 是为了配合shared_ptr而引入的一种智能指针,它不具有普通指针的行为,最大作用在于协助shared_ptr工作
6)unique_ptr:同一时刻只能有一个unique_ptr指向给定对象(通过禁止拷贝语义、只有移动语义来实现),独占对象

8. Static有什么用途?
1)函数体内static变量的作用范围是该函数体,内存只被分配一次,因此它的值在下次调用时不变;如果不存在其他初始化语句,在创建第1个对象时,所有的静态数据都会被初始化为零。不能把静态成员的初始化放置在类的定义中,但可在类的外部通过使用 :: 来重新声明静态变量从而对它进行初始化
2)模块内的static全局变量同样只能在该模块内的函数访问和调用,不能被模块外的其他函数访问
3)在类中的static成员变量属于整个类所有,对类的所有对象只有1份拷贝;静态成员函数内部不能调用非静态成员函数,原因是非静态成员函数需要传入一个this指针,而静态成员函数没有this指针。普通成员变量每个对象都有1份,但是静态成员变量只有1份,被所有对象共享。如果使用sizeof计算对象的大小,计算结果是不包含静态成员变量在内的
4)静态成员函数与普通成员函数的区别:静态成员函数没有 this 指针,只能访问静态成员(静态成员变量和静态成员函数);普通成员函数有 this 指针,可以访问类中任意成员

9. 成员函数用const修饰,其与位置关系意义?
1)同位置无关,修饰的this指针所指向的内存空间,表示该成员变量不能被改变

10. 谈谈对this指针的理解?
1)this指针本质是一个函数参数,平时被隐藏,且它只能在成员函数中使用,全局函数、静态函数都不能使用
2)this在成员函数开始前构造,在成员结束后清除
3)this指针不占用对象的空间

11. C和C++的区别?
1)C主要面向过程,C++面向对象;C是一种结构化语言,重点在于算法和数据结构。C主要考虑通过一个过程将输入进行各种运算后得到输出,C++主要考虑的是如何构造一个对象模型,契合与之相对应的问题域,这样就可以通过获得对象的状态信息得到输出
2)C和C++并不是对立的竞争关系;C++是C语言的加强,是一种更好的C语言;C++是以C语言为基础的,并且完全兼容C语言的特性
3)什么是面向对象:面向对象是一种对现实世界理解和抽象的方法、思想,通过将需求要素转化为对象进行问题处理的一种思想

12. 谈谈struct 和class 的区别?
1)struct作为数据结构实现体,默认数据访问控制是公有的;而class作为类对象实现体,默认数据访问控制是私有的
2)struct默认访问继承权限是public,而后者private
3)class可以用作定义模板参数,而struct不可以
4)C++中struct与class都能实现成员函数、继承、多态

13. new和malloc的区别?
1)都可用来申请动态内存和释放内存,都是在堆(heap)上进行动态的内存操作
2)malloc和free是C语言的标准库函数,new和delete是C++的运算符
3)new会自动调用对象的构造函数,delete会调用对象的析构函数, 而malloc返回的都是void指针
4)运算符是语言自身的特性,它有固定的语义,而且编译器也知道意味着什么。就像 ±*/ ,由编译器解释语义,生成相应的代码;库函数是依赖于库的,没有库就没它,一定程度上独立于语言的。理论上编译器不知道也不关心函数的作用,编译器只保证编译函数,以及调用该函数时参数和返回值符合语法,并生成相应 call 函数的代码。但实际中一些高级点的编译器,都会对标准库自带的一些函数进行特别处理。

14. heap与stack的区别?
1)stack的空间由系统自动分配和释放,存放函数的参数值、 局部变量的值等;heap的空间一般需手动分配和释放,并要指明大小
2)栈空间有限而且是一块连续的内存区域,堆是很大的自由存储区
3)堆栈溢出原因:数组越界, 没有回收内存, 深层次递归调用

15.Vector、List和Deque的区别?
1)Vector是一段连续内存区域,每个元素被顺序存储在内存中,对vector的随机访问效率很高,对非末尾元素的插入和删除则效率低
2)List表示非连续的内存区域并通过一对指向首尾元素的指针双向链接起来,插入删除效率高,随机访问效率低,链式存储结构
3)Deque表示连续内存区域,不同的是它支持高效地在首部插入和删除,通过两级数组结构来实现,一级表示实际容器,第二级指向容器首尾

16.内联函数和宏的差别?
1)内联函数在编译时直接将函数体插入函数调用的地方;inline只是一种请求,编译器不一定允许这种请求
2)内联函数省去了普通函数调用时压栈、跳转和返回的开销;但在某些高级编译其中即使没有inline,也会自动优化程序进行内联编译
3)对短代码来说inline增加空间消耗换来效率提高,这方面和宏是一样的,但是inline在和宏相比没有付出任何额外代价的情况下更安全
4)宏不是函数,是在编译前(编译预处理阶段)将程序中有关字符串替换成宏体;简而言之是简单的文本替换,无编译过程
5)内联函数只有简单的几行,且不含for、 while、 switch等语句;函数体不能过于庞大,不能对函数取址操作

17.const 与 #define的区别?
1)#define N 10 类似于 const int c = 5
2)const常量由编译器处理,提供类型检查与作用域检查;#define由预处理器处理,简单文本替换
3)#define没有作用域,const有明显的作用域,可通过#undef 卸载前者

18. 引用和指针的区别?
1)指针是变量,用于存放地址的变量,指向内存的一个存储单元,引用仅是别名、
2)引用必须初始化,指针不必
3)不存在指向空值的引用,但是存在指向空值的指针
4)sizeof()引用对象得到的是所指对象变量的大小,sizeof() 指针得到是指针本身的大小
5)内存分配上,程序为指针分配内存,不用为引用分配内存

19. 数组与链表的区别?
1)数组逻辑上是连续存储空间;链表是离散内存空间,实用性强
2)数组使用前必须初始化空间大小,但大了可能浪费,小了可能不够;链表相反
3)数组查找及访问数据方便,删除及插入复杂;但链表相反
4)数组一般从栈分配空间,自由度小,方便;链表相反

20. 内存泄漏的产生?
1)已分配的堆内存由于某种原因程序没有释放或者无法释放
2)它具有常发性、偶发性以及一次性等特点
3)使用的时候应记得指针的长度; 分配多少内存应记得释放多少, 保证一一对应的关系; 动态分配内存的指针最好不要再次赋值。

21. 内存溢出的产生?
1)内存溢出是指程序在申请内存时,没有足够的内存空间供其使用
2)内存中加载的数据量过于庞大,如一次从数据库取出过多数据
3)递归调用太深,导致堆栈溢出等
4)内存泄漏最终导致内存溢出

22. 进程和线程的差别?
1)进程是一个在内存中运行的应用程序,如xxx.exe
2)每个进程都有自己独立的一块内存空间,一个进程可以有多个线程
3)线程为进程中的1执行任务,负责当前进程中程序执行。多个线程可共享数据
4)根本区别:进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位
5)详情1如:https://www.jianshu.com/p/a4fa4edbeb8a
6)详情2如:https://blog.csdn.net/kuangsonghan/article/details/80674777

23. TCP和UDP?
1)TCP是传输控制协议,提供的是面向连接、 可靠的字节流服务
2)UDP是用户数据报协议,是一个简单的面向数据报的运输层协议
3)https://blog.csdn.net/li_ning_/article/details/52117463

24.TCP和UDP通信的差别?
1)TCP面向连接,UDP面向无连接的
2)TCP有保障的,UDP传输无保障的
3)TCP是效率低的, UDP效率高的
4)TCP是基于流的,UDP基于数据报文
5)TCP传输重要数据, UDP传输不重要的数据

25.STL库用过吗?常见的STL容器有哪些?算法用过哪几个?
1)容器、算法、迭代器
2)常见容器:vector,list,deque,set,map,stack 和queue
3)序列式容器:每个元素都有固定位置,取决于插入时机和地点,和元素值无关
4)联式容器:元素位置取决于特定的排序准则,和插入顺序无关

26.设计模式懂嘛,简单举个例子?
1)设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。
2)比如单例模式,保证一个类仅有一个实例,并提供一个访问它的全局访问点
3)比如工厂模式,定义一个用于创建对象的接口,让子类决定实例化哪一个类
4)单例模式、工厂模式(简单工厂;工厂方法;抽象工厂)、观察者模式

27.C++中哪些运算符不可以重载?
1) (1) . (2) ?: (3) sizeof (4) :: (5) *

28.memset、memcpy、strcpy和memmove的根本区别?
1)memset,对一段内存空间内全部设置为某个字符,可用来初始化操作
2)memcpy,用来做内存拷贝,可以用来拷贝任何数据类型的对象,可以指定拷贝的数据长度,但需要注意一定要确保内存没有重叠区
3)strcpy,只能拷贝字符串,遇到’\0’就结束拷贝
4)memmove,还是内存拷贝;memcpy是它的子集,且memmove遇到重叠区也能保证拷贝正确;memmove会对拷贝的数据作检查,确保内存没有覆盖,如果发现会覆盖数据,简单的实现是调转开始拷贝的位置,从尾部开始拷贝;而memcpy的实现非常简单,顺序的循环拷贝

29.深度遍历二叉树
1)深度优先搜索算法:沿着树的深度遍历树的节点,尽可能深地搜索树的分支
2)广度优先搜索:又宽度优先搜索,是从根节点开始,沿着树的宽度遍历树的节点,如果所有节点均被访问则算法停止

struct Node
{
    Node *Parent;
    Node *Left,*Right;
};

void Through(Node *Root)
{
    if(Root) printf(Root->data);
    if(Root->Left != null) Through(Root->Left); // 左
    if(Root->Right != null) Through(Root-> Right); // 右
}

30.遍历二叉树方式有哪些?
1)前序遍历【根左右】、中序遍历【左根右】、后序遍历【左右根】、层序遍历
2)“前中”以及“后中”都能唯一确定1颗二叉树、

31.一个数据成员是否可以既是const又是static,如果不行,为什么?
1)一个数据成员可以既是const又是static,表示为静态常量;静态成员一般在类外初始化;常量一般在构造函数后初始化;
2)const static数据成员可以在类内初始化 也可以在类外,不能在构造函数中初始化,也不能在构造函数的初始化列表中初始化
3)static数据成员只能在类外,即类的实现文件中初始化,也不能在构造函数中初始化,不能在构造函数的初始化列表中初始化;
4)const数据成员只能在构造函数的初始化列表中初始化;
5)普通数据成员不能在类内初始化,可以在构造函数中初始化,也可以在构造函数的初始化列表中初始化;
6)https://blog.csdn.net/fengguangle/article/details/78019905

32.构造函数与析构函数的区别?
1)构造函数的名字必须与类名相同
2)构造函数可以有任意类型的参数,但不能有返回类型,可以重载,可以不止一个在类中
3)定义对象时,编译系统会自动调用构造函数
4)构造函数是特殊的成员函数,函数体可以在类体内也可以在类体外
5)构造函数被声明为公有函数,但它不能像其他成员函数那样被显式调用,它是在定义对象的同时被调用的
6)构造函数不能实现多态;理论上可以添加virtual关键词,但功能上实现不了

1)析构函数的名字必须与类名相同,但它前面必须加一个波浪号
2)析构函数没有参数,也没有返回值,而且不能被重载,因此在一个类中只能有一个析构函数
3)当撤销对象时,编译系统会自动调用析构函数
4)析构函数可以是virtual,而构造函数不能是虚函数

33.构造函数为什么一般不定义为虚函数?而析构函数一般写成虚函数的原因 ?
1)构造函数不能为虚函数见前面所述,理论上可以,加了实际中没有意义
2)析构函数一般建议写成虚函数,见前面所述;能够实现通过父类释放及其所有吧子类的内存,防止内存泄漏

34.类成员函数:复制(拷贝)构造函数自动调用的时机有哪几种?
1)对象初始化的2种时机,student A; student B(A)或B=A,简单的浅copy机制实现
2)函数的调用作形参void getheap(student P) {....}
3)作为函数函数返回值时:return P,注意此时返回的对象(又称匿名对象)要看我们后面怎么接;具体如下代码所示:

class student{
public:
	int a
	student() {	}
	student(const student &p){}
	~student() { }
};

studnet get()
{
	student A;
	return p;
}
student B = get();   //扶正匿名对象,匿名对象不释放,因为匿名对象此时就是B
student B;
B = get();    //用匿名对象初始化对象B,然后匿名对象被释放

35.成员函数和友元函数的区别?
1)友元函数以及友元类,都可理解为它们是类的好朋友,因此好朋友所有的变量(主要私有与保护)以及函数又可以被访问;friend 函数
2)友元类是全局函数,不是类成员函数,不能隐式访问类成员,而必须将成员操作符用于作为参数传递的对象
3)成员函数是类定义的一部分,通过特定的对象来调用。成员函数既可以隐式访问调用对象的成员如this指针,而无须使用成员操作符

36.函数模板与函数重载的异同?
1)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值