当前位置:   article > 正文

C++面试总结

C++面试总结

2021 C++面试题

1、虚函数的底层实现原理
1) 构造函数为什么不能是虚函数?
2) 构造函数中能不能调用虚函数?
3) 多重继承下画出虚函数表

2、sizeof结构体对齐
3、static静态变量
static 成员变量属于类,不属于某个具体的对象,即使创建多个对象,也只为它分配一份内存,所有对象使用的都是这份内存中的数据。当某个对象修改了变量,也会影响到其他对象。static 成员变量的内存既不是在声明类时分配,也不是在创建对象时分配,而是在(类外)初始化时分配。反过来说,没有在类外初始化的 static 成员变量不能使用。
4、CretateThread和_beginthreadex区别
5、new和malloc区别,什么样情况选择new?什么情况下选择malloc?频繁malloc造成内存碎片怎么避免?
他们都可用于申请动态内存和释放内存。new/delete比malloc/free更加智能,其实底 层也是执行的malloc/free。为啥说new/delete更加的智能?因为new和delete在对象创建的时候自动执行构造函数,对象消亡之前会自动执行析构函数
内存碎片避免:两级内存机制,当请求内存较大(大于128bytes)时,采用第一级allocator,小于128bytes时,采用第二级allocator,采用内存池的方法管理小内存
6、VS中编译器MT /MD的区别?
7、动态库和静态库的区别?
8、文件系统概念知识
9、VS远程调试代码
10、数据库优化
11、线程同步
12、进程同步
13、互斥锁和临界区的区别?
1) 临界区只能用于对象在同一进程里线程间的互斥访问;互斥体可以用于对象进程间或线程间的互斥访问。
2) 临界区是非内核对象,只在用户态进行锁操作,速度快;互斥体是内核对象,在核心态进行锁操作,速度慢。
3) 临界区和互斥体在Windows平台都下可用;Linux下只有互斥体可用

4) 临界区需要注意:当线程崩溃时候,无法解锁,会处于死锁状态
14、为什么文件映射比传统的write、Read速度快?
15、windebug使用情况
16、map unordered_map的底层实现原理
17、应用程序调用dll的时候,为什么遵循内存谁申请、谁释放的原则?
18、C++ 11新属性,右值引用、转换、完美语义
19、vector 和list的区别使用场景
(1-100万的数据只遍历使用 选用list)
20、windows和Linux检查内存泄漏的方法
21、Qt中 QGraphicsView框架优点?
(图元操作的基本事件都有,能支持单层图元的刷新(widget整个界面都要刷新))
22、model\View的用法使用场景
23、Qt信号与槽机制,源码,信号与槽能连接通的前提条件?
24、Qt中 QThead的用法
25、char* 与 char[] 对比
26、QApplication QGuiApplication QCoreApplication关系(继承关系)
27、QApplication是怎么传递Qt的消息(鼠标移动、放大)
28、QDialog模式对话框和非模式对话框区别,以及消息阻塞
29、TCP三次握手过程,TCP三次握手的过程,accept发生在三次握手的哪一个阶段?
TCP Accept 是三次握手以后,Accept正确返回以后TCP Server 可以和Client的连接已建立并可以通信了
30、TCP建立连接的时候connect()函数和accept()函数分别在三次握手第几次后返回?
在这里插入图片描述
31. Qt基础 (信号与槽、元对象系统、反射、布局)
32. 快速排序的原理、优化
33. Qt4 和 Qt5的区别
1.inline函数可以是虚函数吗?

不能,因为inline函数没有地址,无法放到虚函数表中
       2.静态成员可以是虚函数吗?
       不能, 因为静态成员函数没有this指针, 因为有this指针才能访问到虚表指针,有虚表指针才能找到虚表从而调用实际应该调用的函数。
       3.构造函数可以是虚函数吗?/虚函数指针在什么时候生成的的?
       不能,因为对象中的虚表指针是在构造函数初始化列表阶段才初始化的
       4.析构函数可以是虚函数吗?什么场景下析构函数是虚函数?
       可以,并且最好把基类的析构函数定义成虚函数
       当父类指针指向子类对象时,如果析构函数不是虚函数,析构就只会释放父类对象,造成内存泄漏。(因为析构重名,只能调用一个,调用默认的父类析构函数)
       定义成虚函数后,调用析构时就会取出虚表指针找到实际应该调用的函数。(指针虽然都是父类类型,但是指针内取出的虚表是不一样的,所以析构能调用子类析构)
       5.对象访问普通函数快还是虚函数更快?
       首先如果是普通对象,是一样快的,如果是指针对象或者是引用对象,则调用的普通函数快,因为普通对象在编译时就确定地址了,虚函数构成多态,运行时调用虚函数需要到虚函数表中去查找

算法题
1、链表反转

template <typename T>
typedef struct ListNode
{
   T data;
   struct ListNode* next;
}
void Reverse(ListNode** pList)
{
  ListNode* pre = *pList;
  ListNode* pcur = nullptr;
  ListNode* pTemp = nullptr;
  while(pre){
     pTemp = pre->next;
     pre->next = pcur;
     pcur = pre;
     pre = pTemp;
  }
  (*pList)->next = nullptr;
  *pList = cur;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

2、删除链表中重复的节点

ListNode* deleteDuplicates(ListNode* head) {
        // write code here
        if(head == nullptr){
            return nullptr;
        }
        
        ListNode* temp = head;
        while(temp->next)
        {
            if(temp->val == temp->next->val)
            {
                temp->next = temp->next->next;
            }
            else
                temp = temp->next;
        }
       return head;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

2)删除链表中给定值val的多有节点
输入1->2->6->3->4->5->6 val = 6;
输出1->2->3->4->5

ListNode* removeElements(ListNode* head, int val){ 
    if (head == NULL) {
        return NULL;
    }     
    /* 删除原链表中头节点后面待删除的节点 */
    head->next = removeElements(head->next, val);
    /* 头节点是待删除额节点,返回递归删除更短的链表中待删除的元素后的链表
   否则,返回将递归删除更短的链表中待删除的元素后的链表挂接在头节点后面形成的链表 */
    return head->val == val ? head->next : head;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3、二叉树反转

template <typename T>
typedef struct TreeNode
{
    T data;
    struct TreeNode* left;
    struct TreeNode* right;
};

//方式1 递归实现
TreeNode* InvertTree(TreeNode* root)
{
   if(root){
     InvertTree(root->left);
     InvertTree(root->right);
     std::swap(root->left, root->right);
   }
   return root;
}
//方法2 借助数据结构栈实现
TreeNode* InvertTree(TreeNode* root)
{
   std::stack<TreeNode*>stk;
   stk.push(root);
   while(!stk.empty()){
      TreeNode* p = stk.top();
      stk.pop();
      if(p){
          stk.push(p->left);
          stk.push(p->right);
          std::swap(p->left, p->right);
      }
   }
   return root;
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/672466
推荐阅读
相关标签
  

闽ICP备14008679号