萌新的自我感动前言
这个是我在学C++的时候,通过偶尔看一些大佬们分享的面经中,看到在我的知识点范围内能理解的问题时,我会把这个问题弄懂后,用自己的组织的语言来回答这个问题。
目的一是为了不断积累和巩固知识,二是要锻炼自己的语言表达能力。这篇博客会持续更新我新搜集的问题。这里面有些问题比较简单,但重在怎么把问题说清楚。
1.说下静态和动态多态。
答:
静态多态也叫编译时多态,它是在编译阶段就已经确定了具体要调用的函数,它是通过函数重载和运算符重载来实现的。在编译时,编译器根据参数的类型和数量来确定具体要调用的函数,这种多态的优点就是效率高,因为它是在编译阶段就确定好的,不需要在运行时检查,同时它的缺点也正是因为在编译阶段就确定好,导致它在实际运行时无法根据具体的类型做出动态的变化。
动态多态是指在程序运行时,根据对象的实际类型来确定调用的函数,通过虚函数实现。它的优点是在运行时根据对象的实际类型进行调用,缺点是效率低,因为运行时它要对类型进行检查。
2.说下NULL和nullptr
答:
首先它们都是表示空指针的关键字。
1.NULL它是一个宏定义,它通常被定义为0或者(void*)0,而nullptr它是一个关键字,是由C++11引入的。
2.NULL可以被隐式转化为整数类型,而nullptr不会。
3.NULL的类型一般为整形或者void*,而nullptr为std::nullptr_t.
总之一般建议使用nullptr,它表示空指针时会更纯粹一点,更安全一点。
3.面向对象特性中的多态与继承
答:
继承是通过创建一个父类,然后派生出子类的方法来实现的。子类可以继承父类的属性和函数,同时也可以添加自己的属性和函数,另外子类还可以重写父类中的函数,总之继承本质上就是一种对代码的复用。
多态是指去完成某一个行为时,对于不同的对象会产生不同的效果。它是通过虚函数实现的,使用多态的话,首先子类需要重写父类的函数,然后必须是父类的指针或者引用去指向子类对象,最后当我们调用了重写的函数的时,会调用子类的函数而非父类的,这就达成了多态。
4.野指针是什么?
答:
野指针是指指向了未经分配或者已经被释放的内存的指针,使用野指针会导致程序出现未知的错误。
(补充一下空指针)
空指针是指用0或者nullptr给它显式的赋值了,它不指向任何有效的对象或者函数。
二者区别:
1.内存地址:
野指针的内存地址是不确定的,它可能是无效的,或者是指向已经被释放的内存空间。而空指针指向的内存地址为空。
2.访问行为:
对野指针进行解引用访问可能会出现未知结果或者程序崩溃,访问空指针是安全的,因为它不指向任何内存地址。
3.判断
判断一个指针是否为空指针很容易,直接使用if语句就可以了,但是判断一个指针是否为野指针比较困难。
总结:
答:
空指针是一种明确被定义的状态,它不指向任何对象或者函数;而野指针是一种未定义的状态,它指向的地址可能是无效的或者是已经被释放的。
5.c和c++的区别是什么?
答:
C语言是一种过程式编程语言,它注重的是算法和程序的结构化设计,它提供了基本的数据类型和运算符,它可以底层的访问和操作内存,这就使它的运行性能十分高效,所以C语言特别适合用来开发系统软件,嵌入式等需要高性能且对硬件有较高控制的应用。
C++是在C语言的基础上开发出来的一种面向对象的编程语言,C++兼容C语言,同时它也增加了类,对象,继承,多态等面向对象的特性,因此相比C语言,C++可以更好的组织并管理复杂的代码结构,减少重复代码,并且具备更强大的功能和扩展性。
总之,C语言更关注的是底层结构和程序的性能,它适用与底层要求较高的场景,而C++更强调面向对象编程的思想,它适用与设计和开发复杂的大型项目。
6.动态库,静态库的区别
答:
动态库是程序运行时加载到内存当中,给程序提供调用函数的实现,它是一个共享库,它的优点是体积小,能节省资源。
而静态库它是在编译链接时直接添加到可执行文件中,它让程序具有独立性,并且运行速度相对较快,缺点也就是体积较大,比较占资源。
7.多态的实际应用
答:
多态是父类指针或者引用指向子类对象,实现了完成同一个行为,不同的对象会带来不同的效果的场景。
1.多态可以使代码更具有灵活性,它可以根据对象的不同而调用不同的函数。
2.多态可以简化代码,可以将通用的代码写进父类,提高了代码的复用性。
3.多态还可以实现接口和抽象类,提高了代码的可扩展性,可维护性。
4.多态还是设计模式的基础。
但它也有些缺点,因为它运行时需要动态绑定,所以会有一定的性能消耗。
在使用多态时对父类的设计有一定的要求,如果父类设计不合理,会导致子类设计困难或者产生代码重复。
还有在调式的时候也会比较困难,如果不能很好的理解多态,可能会难以定位问题的所在。
8.new和malloc的区别(也是delete和free的主要区别)
答:
首先它们相同的点都是从堆上动态开辟空间,需要用户手动释放,不同的是
1.malloc是函数,new是运算符。
2.malloc申请的空间不会初始化,new申请的空间会初始化。
3.malloc申请空间需要手动计算大小,而new后面只需要跟数据类型就可以了,多个对象需要加[]来指定对象个数。
4.malloc的返回值是void*,使用时要强转,new不需要,因为后面跟的是空间的类型。
5.malloc申请空间失败时返回NULL,所以使用时需要判空,而new申请空间失败了会抛异常,抛出异常后需要捕获。
6.申请自定义空间时,malloc只会开空间,不会调用构造函数,而new不仅会开空间,还会调用构造函数。
9.vector的底层原理?
vetcor是一个动态数组,它是用一块连续的内存空间来存储元素。
vetcor有一个size来跟踪当前元素的数量,还有一个capacity来维护当前数组的大小。
当vector增加的元素超过了当前数组的大小时,vector会动态扩容。根据平台的不同,每次扩容的倍数也可能不一样,比如在linux下是二倍扩容,在VS下是1.5倍扩容。
vector里面重写了方括号([]),我们可以像访问数组那样通过下标直接访问元素。也可以用at()函数通过下标来进行访问。因为它是随机访问,所以效率是O(1).
vector支持插入和删除,其中尾删和尾插效率是O(1)。
10.C++的特化和偏特化
答:
特化就是定义模板时使用特定的类型或者特定的模板参数。
偏特化就是不完全的特化,它定义的模板参数中既有类也有具体的数据类型。
特化一般用来处理特殊的类型。
代码示例:
// 模板特化示例
template<typename T>
void printData(T data) {
cout << "Generic template: " << data << endl;
}
template<>
void printData<int>(int data) {
cout << "Specialized template for int: " << data << endl;
}
// 使用模板特化
printData(10); // 输出: Specialized template for int: 10
printData("Hello"); // 输出: Generic template: Hello
// 偏特化示例
template<typename T, typename U>
struct Pair {
T first;
U second;
};
template<typename T>
struct Pair<T, int> {
T first;
int second;
};
// 使用偏特化
Pair<int, float> p1; // 类型为 Pair<int, float>
Pair<int, int> p2; // 类型为 Pair<int, int>
11. define 和 inline 的区别
答:
define是C++和C的关键字,它用于定义宏。它在代码编译之前进行文本替换,将宏名替换为其定义的内容。
inline是C++的关键字。它用于修饰函数,建议编译器把该函数设置成内联函数。内联函数可以减少函数调用的开销,提高性能。但是如果函数过长,编译器就会忽视这个建议。
12.虚函数底层原理
虚函数的底层实现围绕两个重要的概念:虚函数表和虚函数表指针。
当一个类包含虚函数时,编译器会为该类生成一个虚函数表,虚函数表中存放着虚函数的地址,在VS下一般最后一个会存空地址。虚函数表一般存在常量区。
当这个包含虚函数的类被创建时,会生成一个虚函数表指针,它指向这个虚函数表,在虚函数表中通过偏移量来找到需要调用的虚函数,多态就是通过父类的指针或者引用,在子类对象中通过虚函数表指针找到虚函数表,以此来访问子类函数,从而达到多态。
13.面试手撕题注意
比如这道题,在delete那里,如果是笔试的话,就不要写;如果是面试的话,要先问一下面试官这个结点是不是new出来的,如果是,那么就加上delete;如果不是,那我们delete反而会报错。
14.说下STL的组成
STL由六大组件组成:容器,算法,迭代器,仿函数,适配器,空间配置器。
关系如下:
其中设计的最好的是迭代器,理由如下: