整体感觉面试和想象中的一样 主要是第一次比较正规的面试
面试的主要内容就是根据我的简历来问的 虽然dy网上评价不是很好 但是面试整体没啥大问题
主要是第一次真的比较紧张 说话吞吞吐吐含糊不清
(PS:面试官长得有点像红衣教主)
建议真的需要准备一下 我这个就是一下子不会讲了 感觉这个特别影响第一印象
(1)class和struct 本身成员的默认访问级别不同,是最本质的特点(这块我之前有知道,但是具体的不同忘记了,就谈了pubilc、protect、private)。结构体的成员和成员函数在默认情况下的访问级别是公有的(public),类的成员和成员函数在默认情况下的访问级别是私有的(private)。
(2)两者在赋值上存在不同
struct A{char c1; int n2; float db3;};A a = {'a',1,3.14};
这样可以直接给结构体赋值,没有任何错误,但是并不可以给类赋值。我们平时使用{}来对结构赋值,是一个初始化列表形式进行初始化,这样简单的初始化只能用在简单的数据结构上,如果加上构造函数,那么struct会表现出一种对象的特性,因此再使用这种方式赋值就会失效。也就是说当我们在一个结构中加入构造函数后,结构体的内部结构会发生变化;但加入一个普通函数,结构体内部结构依旧不变;因此可以理解为普通函数是一种对数据结构的算法,并不会打破原本数据的特性。
(1)智能指针:在构造的时候分配内存,当离开作用域的时候,自动释放分配的内存,这样的话开发人员就可以从手动动态管理内存的繁杂内容中解放出来。(重点注意!!)
(2)野指针:指向非法的内存地址指针叫作野指针(Wild Pointer),也叫悬挂指针(Dangling Pointer),意为无法正常使用的指针。
野指针产生的原因:
a. 指针变量未初始化或者随便赋值:指针变量没有初始化,其值是随机的,也就是指针变量指向的是不确定的内存,如果对它解除引用,结果是不可知的。
b. 指针释放后未置空:有时候指针在释放后没有复制为 nullptr,虽然指针变量指向的内存被释放掉了,但是指针变量中的值还在,这时指针变量就是指向一个未知的内存,如果对它解除引用,结果是不可知的。
c. 指针操作超出了变量的作用域:函数中返回了局部变量的地址或者引用,因为局部变量出了作用域就释放了,这时候返回的地址指向的内存也是未知的。
如何避免野指针:
a. 指针变量一定要初始化,可以初始化为 nullptr,因为 nullptr 明确表示空指针,对 nullptr 操作也不会有问题。
b. 释放后置为 nullptr。
C++11:(1)引入了 auto 关键字和 decltype 关键字,用于自动推导变量类型;(2)引入了 lambda 表达式,用于定义匿名函数;(3)引入了智能指针,例如 shared_ptr 和 unique_ptr,用于自动管理内存;(4)引入了可变参数模板,允许模板参数数量可变;(5)引入了右值引用和移动语义,用于提高代码效率。 C++14:(1)改进了泛型编程,引入了泛型 lambda 表达式;(2)引入了二进制字面量和通用的 lambda 捕获初始化; (3)改进了 constexpr 函数,允许函数内包含控制流语句。 C++17:(1)引入了 if constexpr 语句,允许在编译期间进行条件判断;(2)引入了折叠表达式,简化了变长参数模板的实现;(3)改进了模板参数推导规则,支持类模板参数推导。 C++20:(1)引入了概念(Concepts),用于限定模板参数的类型;(2)引入了协程(Coroutines),用于实现异步编程;(3)引入了三向比较运算符(Three-way Comparison),用于简化比较操作;(4)引入了格式化输出库(std::format),用于格式化输出字符串。
(1)静态的多态:函数重载,看起来调用同一个函数却有不同的行为。静态:原理是编译时实现。
(2)动态的多态:一个父类的引用或指针去调用同一个函数,传递不同的对象,会调用不同的函数。动态:原理是运行时实现。
(3)虚函数:即被virtual修饰的类成员函数称为虚函数。 一旦定义了虚函数,该基类的派生类中同名函数也自动成为了虚函数。也就是说在派生类中有一个和基类同名的函数,只要基类加了virtual修饰,派生类不加virtual修饰也是虚函数。 虚函数只能是类中的一个成员函数,不能是静态成员或普通函数。
当 vector 的大小和容量相等也就是满载时,如果再向其添加元素,那么 vector 就需要扩容。
vector 容器扩容的过程需要经历以下 3 步: (1) 完全弃用现有的内存空间,重新申请更大的内存空间; (2)将旧内存空间中的数据,按原有顺序移动到新的内存空间中; (3) 最后将旧的内存空间释放。
因为vector扩容需要申请重新申请新的空间,但是扩容以后它的内存地址会发生变化,这样进行扩容是非常耗时的,为了降低时间车成本,每次扩容时候都会申请比用户需求更多的内存空间,以便后期使用。
可以利用快慢指针来实现,让慢指针每次向下移动一个节点,让快指针每次向下移动两个节点,如果快慢指针可以重合表示在链表中有环,否则则表示无环。
面向对象的三大特征:封装、继承、多态
(1)封装:将数据以及对数据的操作保护起来,隐藏其操作过程,只对外呈现操作的接口,由public,protect,privare三个级别,很好的保证了代码的安全性
(2)继承:一个B类继承A类,B类中含有A类的一些属性,这表现了共性,B类中还可以添加一些属于自己的属性,这体现了个性,继承可以很好的实现代码的复用和拓展性,同时继承也是多态的前提
(3)多态:多态是指基类的指针或引用,在运行时动态的调用实际绑定对象函数的行为。基类指针绑定基类对象就调用基类方法,基类指针绑定派生类对象就调用派生类方法,多态提高了代码的可读性和组织性。
很简单的找子集的问题
题目链接:**************************************************
/* 我第一反应是可以利用递归进行解决 但是后面去看了一下迭代法实现子集枚举更简单 */ class Solution { public: vector<int>t; vector<vector<int>>ans; void dfs(int cur,vector<int>&nums){ if(cur==nums.size()){ ans.push_back(t); return ; } t.push_back(nums[cur]); dfs(cur+1,nums); t.pop_back(); dfs(cur+1,nums); } vector<vector<int>> subsets(vector<int>& nums) { dfs(0,nums); return ans; } };