cpp面经(杂乱版)

Last updated on June 3, 2024 pm

什么是虚函数?
virtual 关键字修饰的成员函数称为虚函数。
虚函数的作用是实现多态性,即通过基类访问派生类的函数。
什么是纯虚函数?
在虚函数后面添加 =0 ,虚函数就成为纯虚函数
在很多情况下,基类生成对象很不合理。为了解决这个问题,引入了纯虚函数的概念,将函数定义为纯虚函数,派生类中必须重写实现纯虚函数。对于实现了纯虚函数的子类,该纯虚函数在子类中就变成了虚函数。

auto_ptr能作为vector的元素吗?为什么?

答:不可以。
当复制一个auto_ptr时,它所指向的对象的所有权被交到复制的auto_ptr上面,而它自身将被设置为null。复制一个auto_ptr意味着改变它的值。

死锁的四个必要条件

1、 互斥条件:进程要求对所分配的资源(如打印机)进行排他性控制,即在一段时间内某资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。

2、不可剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能由获得该资源的进程自己来释放(只能是主动释放)。

3、 请求与保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。

4、循环等待条件:存在一种进程资源的循环等待链,链中每一个进程已获得的资源同时被链中下一个进程所请求。

预防:通过设置某些限制条件,以破坏产生死锁的条件,来防止发生死锁。
避免:系统在分配资源时根据资源的使用情况提前作出预测,从而避免死锁的发生。
检测:允许系统在运行的过程中产生死锁,但是,系统中有相应的管理模块可以及时检测出已经产生的死锁,并且精确地确定与死锁有关的进程和资源,然后采取适当措施,清除系统中已经产生的死锁。
解除:与检测死锁相配套的一种措施,用于将进程从死锁状态下解脱出来。

进程调度

在多道程序系统中,进程的数量往往多于处理机的个数,因此进程争用处理机的情况在所难免。处理机调度是对处理机进行分配,即从就绪队列中按照一定的算法(公平、高效)选择一个进程并将处理机分配给它运行,以实现进程并发执行。

先来先服务(FCFS)调度算法、短作业优先(SJF)调度算法、优先级调度算法、高响应比优先调度算法

进程与线程的区别

本质区别:进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位。

包含关系:一个进程至少有一个线程,线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。

资源开销:每个进程都有独立的地址空间,进程之间的切换会有较大的开销;线程可以看做轻量级的进程,同一个进程内的线程共享进程的地址空间,每个线程都有自己独立的运行栈和程序计数器,线程之间切换的开销小。

影响关系:一个进程崩溃后,在保护模式下其他进程不会被影响,但是一个线程崩溃可能导致整个进程被操作系统杀掉,所以多进程要比多线程健壮。

一个基本的事实前提一个CPU在一个瞬间只能处理一个任务

并发(Concurrent):在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行。
同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得在宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干段,使多个进程快速交替的执行。

并行(Parallel):当系统有一个以上CPU时,当一个CPU执行一个进程时,另一个CPU可以执行另一个进程,两个进程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。其实决定并行的因素不是CPU的数量,而是CPU的核心数量,比如一个CPU多个核也可以并行。

image-20240509203458598

哈希冲突

当两个不同的数经过哈希函数计算后得到了同一个结果,即他们会被映射到哈希表的同一个位置时,即称为发生了哈希冲突。简单来说就是哈希函数算出来的地址被别的元素占用了。

开放定址法:我们在遇到哈希冲突时,去寻找一个新的空闲的哈希地址。(链地址法、公共溢出区法)

数据库索引
堆栈的区别

1
2
3
4
5
6
7
8
一个由c/C++编译的程序占用的内存分为以下几个部分 
1、栈区(stack)― 由编译器自动分配释放。用来存储函数调用时的临时信息的结构,存放为运行时函数分配的局部变量、函数参数、返回数据、返回地址等。
2、堆区(heap) ― 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。
注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)―,全局变量和静态变量的存储是放在一块的,
初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放
4、文字常量区 ―常量字符串就是放在这里的。 程序结束后由系统释放
5、程序代码区―存放函数体的二进制代码。

栈和队列的区别、数组和链表有什么区别

image-20240509163720074

c语言中常用的数据结构
两个堆怎么实现一个队列
二叉树的前中后序遍历输出结果

  • HashMap原理,为什么每次扩容都是2的倍数,为什么由头插改成了尾插,环化是怎么引起的

  • 快排和堆排的原理

    当面试官询问 C++ 相关的常见八股知识时,他们可能会深入以下几个方面:

    1. C++ 的特性和优势

      • C++ 是一种通用编程语言,继承了 C 语言的功能并加入了面向对象编程的特性。
      • C++ 具有高效性、灵活性和可移植性等优势,可以直接操作硬件并实现高性能的应用程序。
    2. 类与对象

      • 类是用户自定义的数据类型,用于描述具有相同属性和行为的对象的集合。
      • 对象是类的一个实例,具有类定义的属性和行为。
      • 构造函数用于初始化对象的状态,析构函数用于清理对象所占用的资源。
    3. 继承与多态

      • 继承是面向对象编程中一种机制,允许一个类继承另一个类的属性和行为。
      • 多态性允许不同对象对同一消息做出不同的响应,提高了代码的灵活性和可扩展性。
      • 虚函数是在基类中声明的带有 virtual 关键字的函数,派生类可以重写这些函数以实现多态。
    4. 模板与泛型编程

      • 模板是一种通用的代码结构,可以用于生成特定数据类型的函数或类。
      • 模板的特化和偏特化允许针对特定类型提供定制的实现。
      • 泛型编程是一种编程范式,旨在编写与特定数据类型无关的代码。
    5. 异常处理

      • 异常是程序执行过程中发生的意外事件。
      • 异常处理是一种机制,用于在程序中检测、报告和处理异常。
      • C++ 中的异常处理关键字包括 try、catch 和 throw。
    6. 内存管理

      • 栈是一种自动分配和释放内存的数据结构,用于存储函数调用、局部变量等。
      • 堆是一种动态分配和释放内存的数据结构,用于存储程序运行时动态创建的对象。
    7. STL(标准模板库)

      • STL 提供了丰富的数据结构和算法,包括向量、链表、映射、集合等容器以及排序、搜索、迭代等算法。
      • 迭代器是一种抽象的数据访问接口,用于遍历容器中的元素。
    8. 并发编程

      • C++11 引入了一套新的并发编程库,包括线程、原子操作、互斥量、条件变量等。
      • 线程同步的机制包括互斥量、条件变量和原子操作,用于确保多个线程之间的数据一致性和同步执行。

    以上是对常见 C++ 八股知识的详细解答,你可以根据自己的理解和经验进一步扩展和完善。

  • 重载重写隐藏

    一、重载

    • 相同的作用域内
    • 参数列表不同(参数的类型,个数,顺序不同)
    • 函数名字相同;函数返回类型相同

    二、重写

    • 不在同一个作用域(分别位于派生类与基类) ;
    • 基类函数必须有 virtual 关键字,不能有 static 。
    • 函数名字相同;参数相同;返回值相同
    • 函数体不同

    三、隐藏

    ​ 不在同一个作用域(分别位于派生类与基类) ;

    ​ 函数名字相同;

    ​ 参数、返回值、函数体都可以不同;

  • 什么函数可以/不可以声明为虚函数

析构函数 普通的成员函数

​ 普通函数(非成员函数)、构造函数、内联函数、静态函数、友元函数。

  • vector和list的使用场景

    vector适用:对象数量变化少,简单对象,随机访问元素频繁
    list适用:对象数量变化大,对象复杂,插入和删除频繁
    最大的区别是,list是双向的,而vector是单向的。
    因此在实际使用时,如何选择这三个容器中哪一个,应根据你的需要而定,一般应遵循下面的原则:
    1)、如果你需要高效的随即存取,而不在乎插入和删除的效率,使用vector
    2)、如果你需要大量的插入和删除,而不关心随即存取,则应使用list
    3)、如果你需要随即存取,而且关心两端数据的插入和删除,则应使用deque。

  • stack适配器的底层容器是什么,能不能用vector,为什么

1 stack 堆栈适配器 ( 可用的容器类型 vector deque list)默认是deque
2 queue 队列适配器 ( 可用的容器类型 deque list)默认的容器是deque
3 priority_queue 优先级队列 (可用的容器类型 deque vector)默认是vector|
底层容器必须支持随机访问迭代器,因此底层容器可以是deque,不能是list

  • 什么情况下需要使用多继承

一个子类拥有很多父类 ,一般指一个类有2个以上父类。

  • STL中的多继承
  • 虚继承原理

所谓虚继承(virtual)就是子类中只有一份间接父类的数据。该技术用于解决多继承中的父类为非虚基类时出现的数据冗余问题,即菱形继承问题。

在上图中,父类数据并不存放在虚继承的子类中,那么子类怎么找到父类数据呢?

——在虚继承的类中,会定义一个虚基表指针vbptr指向虚基表。(虚表在构造函数之前写入)

而虚基表中会存在偏移量,这个量就是表的地址到父类数据地址的距离

我们可以通过调试,找到虚基表指针和虚基表:

  • 右值引用和移动语义

可以被取地址的、有名字的都是左值,反之不能取地址的、没有名字的就是右值。

右值:字面常量,表达式,函数的非引用返回值,在表达式求值过程中临时创建的对象,这些使用过后就被销毁的资源

在现有的 C++ 机制中,我们可以定义拷贝构造函数和赋值函数。要实现转移语义,需要定义转移构造函数,还可以定义转移赋值操作符。如果转移构造函数和转移拷贝操作符没有定义,那么就遵循现有的机制,拷贝构造函数和赋值操作符会被调用。普通的函数和操作符也可以利用右值引用操作符实现转移语义。

  • C++内存管理方式

image-20240509170056071

一、自动存储

在函数内部定义的常规变量使用自动存储空间,被称为自动变量(automatic variable),这意味着它们在所属的函数被调用时自动产生,在该函数结束时消亡。自动变量通常存储在栈中。这意味着执行代码块时,其中的变量将依次加入到栈中,而在离开代码块时,将按相反的顺序释放着些变量,着被称为后进先出(LIFO)。因此,在程序执行过程中,栈将不断地增大和缩小。

二、静态存储

静态存储是整个程序执行期间都存在的存储方式。使变量称为静态的方式有两种:一种是在函数外面定义它;另一种是在声明变量时使用关键字static

三、动态存储
new和delete运算符提供了一种比自动变量和静态变量更灵活的方法。它们管理了一个内存池,这在C++中被称为自由存储空间(free store)或堆(heap)。该内存池同用于静态变量和自动变量的内存是分开的。new和delete让您能够在一个函数中分配内存,而在另一个函数中释放它。因此,数据的声明周期不完全受程序或函数的生命时间控制。与使用常规变量相比,使用new和delete让程序员对程序如何使用内存有更大的控制权。然而,内存管理也更复杂了。在栈中,自动添加和删除机制使得占用的内存总是连续的,单new和delete的相互影响可能导致占用的自由存储区不连续,这使得跟踪新分配内存的位置更困难。

四、线程存储

  • shared ptr的具体实现(问的很细

栈、堆、内存泄漏
如果使用new在自由存储空间(或堆)上创建变量后,没有调用delete。会发生什么?

即使包含指针的内存(由于作用域规则和对象生命周期的原因而)被释放,在自由存储空间上动态分配的变量或结构依然存在。

则将会无法访问自由存储空间的结构,因为指向这些内存的指针无效。

这将导致内存泄露,被泄漏的内存在程序的整个生命周期将不可使用,这些内存被分配,但无法被使用。

引用和指针的区别

\1. 指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元;而引用仅是个别名;

\2. 引用使用时无需解引用(*),指针需要解引用;

\3. 引用只能在定义时被初始化一次,之后不可变;指针可变;

\4. 引用没有 const,指针有 const;

\5. 引用不能为空,指针可以为空;

\6. “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身的大小;

\7. 指针和引用的自增(++)运算意义不一样;

\8. 指针可以有多级,但是引用只能是一级(int **p;合法 而 int &&a是不合法的)

9.从内存分配上看:程序为指针变量分配内存区域,而引用不需要分配内存区域。

tcp滑动窗口

滑动窗口机制是TCP协议中实现流量控制和可靠传输的关键技术。它的主要工作原理如下:

  1. 发送方维护一个发送窗口,这是一个连续的字节序列,表示发送方可以发送的字节数范围。发送窗口由两个参数定义:窗口的起始字节和窗口的大小。发送方将数据分成多个数据段,并按顺序发送到接收方。
  2. 接收方使用确认号来通知发送方已成功接收到的数据。确认号表示接收方期望接收的下一个字节的序列号。同时,接收方还会通告一个窗口大小,告诉发送方自己的接收缓冲区还能容纳多少字节的数据。
  3. 发送方根据接收方通告的窗口大小进行数据发送控制。如果接收方的窗口变大,发送方可以发送更多的数据;如果接收方的窗口变小,发送方需要适应减少的窗口大小。这样,发送方可以持续发送数据而不需要等待每个数据段的确认,从而提高了传输效率。

滑动窗口机制在数据传输中起到了流量控制和可靠性传输的重要作用。通过动态调整窗口大小,接收方可以控制发送方的数据发送速率,避免网络拥塞和数据丢失。同时,滑动窗口机制还确保了数据的顺序传输和可靠接收,为TCP协议提供了可靠的传输服务。

二分查找的时间复杂度、二分查找的具体操作

O(logn)

1
2
3
4
5
6
while (L < R){                      //一直二分,直到区间[L,R]缩小到L=R
int mid = (L + R) / 2; //mid是L、R的中间值
if (check(mid)) R = mid; //答案在左半部分[L,mid],更新R=mid
else L = mid + 1; //答案在右半部分[mid+1, R],更新L=mid+1
}

11.n个数中找出最小的k个数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
vector<int> ret;
if(k == 0 || input.size() < k)
return ret;
priority_queue<int,vector<int> > pq;(大根堆)
for(int i=0; i< input.size(); i++){
if(pq.size() < k)
pq.push(input[i]);
else{
if(input[i] < pq.top()){
pq.pop();
pq.push(input[i]);
}
}
}
while(!pq.empty()){
ret.push_back(pq.top());
pq.pop();
}
return ret;
}
};

priority_queue<int,vector,greater >q; (小根堆)

为什么父类的析构函数为什么不调用子类的虚函数(因为子类早就被析构了)
IO多路复用select/poll/epoll
什么情况下select比epoll好

全局变量和static全局变量有啥不同

1.两者作用域不同,全局变量的作用域是整个工程项目,静态全局变量作用域只在当前文件

2.全局变量在其他文件引用时,需使用extern声明

3.全局变量和静态全局变量都存储在静态存储区

4.全局变量和静态全局变量都是定义在函数外或类外

define和type define的不同

1、作用域不同
#define没有作用域的限制,只要是之前预定义过的宏,在以后的程序中都可以使用。
typedef有自己的作用域,只能在作用域内使用。

2、对指针的操作不同
例如:

typedef int* INTp1 ;

#define INTp2 int* ;
上面两种看似效果一样,实则不同!具体区别如下:
INTp1 a,b等同于int *a; int *b;表示定义了两个整型指针变量。
而INTp2 a,b等同于int *a, b; 表示定义了一个整型指针变量a和整型变量b。

3、 功能不同
#define 虽然只是简单的替换,但是也可为为类型取别名,还可以定义常量、变量和编译开关等;
typedef可用来定义类型的别名,这些类型不只包含内部类型(int,double,long long,char等),还包括自定义类型(如struct),可以起到使类型易于记忆的功能,增强程序的可读性。

4、原理不同
define不分配内存,给出的是⽴即数,有多少次使⽤就进⾏多少次替换。

typedef在静态存储区中分配空间,在程序运⾏过程中内存中只有⼀个拷贝。

互斥锁

互斥锁、自旋锁和读写锁用于解决多线程同步的问题

sizeof和strlen的区别

violate关键字

14.set的使用场景,map使用场景

set可以做到整数数组的去重,但是对象就不可以。
map中的集合,元素成对存在,每个元素由键和值两部分组成。

问2:C和C++的区别?

答:c++在c的基础上增添类,C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现过程(事务)控制),而对于C++,首要考虑的是如何构造一个对象模型,让这个模型能够契合与之对应的问题域,这样就可以通过获取对象的状态信息得到输出或实现过程(事务)控制。

1.
语言本身:

  1. C++是面向对象语言,C是面向过程语言。
  2. 结构:C以结构体struct为核心结构;C++以类class为核心结构。
  3. 多态:C可以以宏定义的方式“自定义”部分地支持多态;C++自身提供多态,并以模板templates支持编译期多态,以虚函数virtual function支持运行期多态。
  4. 头文件的调用:C++用< >代替” “代表系统头文件;且复用C的头文件时,去掉”.h”在开头加上”C”。
  5. 输入输出:鉴于C++中以对象作为核心,输入和输出都是在流对象上的操作。
  6. 封装:C中的封装由于struct的特性全部为公有封装,C++中的封装由于class的特性更加完善、安全。
  7. 常见风格:C中常用宏定义来进行文本替换,不具有类型安全性;C++中常建议采用常量定义,具有类型安全性。
  8. 效率:常见的说法是同等目的C通常比C++更富有效率(这其实有一定的误解,主要在于C++代码更难于优化且少有人使用编译期求值的特性)。
  9. 常用语言/库特性:
    1. 数组:C中采用内建数组,C++中建议采用vector。相比之下vector的大小可以动态增长,且使用一些技巧后增长并不低效,且成员函数丰富。
    2. 字符串 C中采用C风格的string(实则为字符串数组),C++中建议采用string,对比与上一条类似。
    3. 内存分配:C中使用malloc与free,它们是是C标准库函数,C++中建议使用new/delete代替前者,他们说是C++的运算符(这是笔试面试常考点)以C++中的new为例,new可分为operator new(new 操作)、new operator(new 操作符)和placement new(定位 new)。其中operator new执行和malloc相同的任务,即分配内存,但对构造函数一无所知;而 new operator则调用operator new,分配内存后再调用对象构造函数进行对象的构造。其中operator new是可以重载的。placement new,就是operator new的一个重载版本,允许你在一个已经分配好的内存中构造一个新的对象。
    4. 指针:C中通常使用的是原生指针(raw pointer),由于常出现程序员在申请后忘记释放造成资源泄漏的问题,在C++98中加入了“第一代”基于引用计数的智能指针auto_ptr,由于初代的各种问题(主要是无法解决循环指针),在03标准也就是TR1中引入了shared_ptr,weak_ptr和unique_ptr这三个功能各异的智能指针,并与11标准中正式确定,较好的解决了上述问题。
  10. 仅有C++才有的常用特性:
    1. 语言(范式)特性:
      1. 面向对象编程:C++中以关键字class和多态特性支持的一种编程范式;
      2. 泛型编程:C++中以关键字template支持的一种编程范式;
      3. 模板元编程 :C++中以模板特化和模板递归调用机制支持的一种编程范式。
      4. C++中以对象和类型作为整个程序的核心,在对象方面,时刻注意对象创建和析构的成本,例如有一个很常用的(具名)返回值优化((N)RVO);
        在类型方面,有运行时类型信息(RTTI)等技术作为C++类型技术的支撑。
      5. 函数重载:C++允许拥有不同变量但具有相同函数名的函数(函数重载的编译器实现方式、函数重载和(主)模板特化的区别都曾考过)。
      6. 异常:以catch、throw、try等关键字支持的一种机制。
      7. 名字空间:namespace,可以避免和减少命名冲突且让代码具有更强的可读性。
      8. 谓词用法:通常以bool函数或仿函数(functor)或lambda函数的形式,出现在STL的大多数算法的第三个元素。
    2. 常见关键字(操作符)特性:
      1. auto:在C中,auto代表自动类型通常都可省略;而在C++11新标准中,则起到一种“动态类型”的作用——通常在自动类型推导和decltype搭配使用。
      2. 空指针:在C中常以NULL代表空指针,在C++中根据新标准用nullptr来代表空指针。
      3. &: 在C中仅代表取某个左值(lvalue)的地址,在C++中还可以表示引用(别名)。
      4. &&:在C中仅能表示逻辑与,在C++中还可以表示右值引用。
      5. []:在C中仅能表示下标操作符,在C++中还可以表示lambda函数的捕捉列表。
      6. {}:在C中仅能用于数组的初始化,在C++中由于引入了初始化列表(initializer_list),可用于任何类型、容器等的初始化。
      7. 常量定义:C中常以define来定义常量,C++中用const来定义运行期常量,用constexpr来定义编译器常量。
    3. 常用新特性:
      1. 右值引用和move语义(太多内容,建议自查)。
      2. 基于范围的for循环(与python中的写法类似,常用于容器)。
      3. 基于auto——decltype的自动类型推导。
      4. lambda函数(一种局部、匿名函数,高效方便地出现在需要局部、匿名语义的地方)。
      5. 标准规范后的多线程库。

问3:什么是面向对象(OOP)?

答:面向对象是一种对现实世界理解和抽象的方法、思想,通过将需求要素转化为对象进行问题处理的一种思想。面向对象就是把现实问题抽象为对象,通过调用每个对象的属性或功能去解决问题。

对象
对象是由数据(描述事物的属性)和作用于数据的操作(体现事物的行为)组成的封装体,描述客观事物的一个实体,是构成系统的基本单元。


类是对一组有相同数据和相同操作的对象的定义,是对象的模板,其包含的方法和数据描述一组对象的共同行为和属性。类是在对象之上的抽象,对象则是类的具体化,是类的实例。类可有其子类,也可有其他类,形成类层次结构。1)类是对象的抽象,而对象是类的具体实例。类是抽象的,不占用内存,而对象是具体的,占用存储空间。

2)类是一组具有相同属性和行为的对象的抽象。我们可以将类看做是创建对象蓝图,对象根据这个蓝图去具体实现某个东西。

问4:什么是多态?

答:多态是指相同的操作或函数、过程可作用于多种类型的对象上并获得不同的结果。不同的对象,收到同一消息可以产生不同的结果,这种现象称为多态。

问5:设计模式懂嘛,简单举个例子?

答:设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。

比如单例模式,保证一个类仅有一个实例,并提供一个访问它的全局访问点。将构造函数、析构函数、复制构造函数、赋值操作符声明为私有,即可实现单例模式

适用于:当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时;当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。

比如工厂模式,定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使一个类的实例化延迟到其子类。

适用于:当一个类不知道它所必须创建的对象的类的时候;当一个类希望由它的子类来指定它所创建的对象的时候;当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。

问8:const知道吗?解释其作用。

答:

1.const 修饰类的成员变量,表示成员常量,不能被修改。

2.const修饰函数承诺在本函数内部不会修改类内的数据成员,不会调用其它非 const 成员函数。

3.如果 const 构成函数重载,const 对象只能调用 const 函数,非 const 对象优先调用非 const 函数。

4.const 函数只能调用 const 函数。非 const 函数可以调用 const 函数。

5.类体外定义的 const 成员函数,在定义和声明处都需要 const 修饰符。。

问12:解释下封装、继承和多态?

答:

一、封装:

封装是实现面向对象程序设计的第一步,封装就是将数据或函数等集合在一个个的单元中(我们称之为类)。封装(encapsulation)即信息隐蔽。它是指在确定系统的某一部分内容时,应考虑到其它部分的信息及联系都在这一部分的内部进行,外部各部分之间的信息联系应尽可能的少。

封装的意义在于保护或者防止代码(数据)被我们无意中破坏。

  • public:对外公开,访问级别最高
  • protected:只对同一个包中的类或者子类公开
  • 默认:只对同一个包中的类公开
  • private:不对外公开,只能在对象内部访问,访问级别最低

二、继承:

让某个类型的对象获得另一个类型的对象的属性和方法。继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

继承主要实现重用代码,节省开发时间。

子类可以继承父类的一些东西。

三、多态

多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。多态:对于同一个行为,不同的子类对象具有不同的表现形式。多态存在的3个条件:
1)继承 2)重写 3)父类引用指向子类对象。

问15:常用的排序算法有哪些?简单描述几个排序算法的优缺点?

答:选择、冒泡、快速、**、希尔、归并、堆排等。

1.快排:是冒泡排序的一种改进。

优点:快,数据移动少

缺点:稳定性不足

2.归并:分治法排序,稳定的排序算法,一般用于对总体无序,但局部有序的数列。

优点:效率高O(n),稳定

缺点:比较占用内存

问16:new和malloc的区别?

答:

1、new是关键字,需要编译器支持;malloc是库函数,需要头文件支持。

2、new申请内存无需指定内存大小,编译器会根据类型信息自行计算。除此之外,new会调用构造函数。malloc必须由我们计算需要申请的字节数,需要显式指出所需内存的尺寸,并且返回后强行转换为实际类型的指针。而且malloc只管分配内存,并不能对所得的内存进行初始化,所以得到的一片新内存中,其值是随机的。

3、new可以重载,malloc不可以重载。

4、new是关键字,malloc是库函数,new的效率高于malloc。
new和malloc都可用于申请动态内存和释放内存。对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。 C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。所以说new的效率高于malloc。

5、new出来的指针是直接带类型信息的。而malloc返回的都是void指针。

问18:同步IO和异步IO的区别?

答:

A. 同步

所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。

按照这个定义,其实绝大多数函数都是同步调用(例如sin isdigit等)。

但是一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。

最常见的例子就是 SendMessage。

该函数发送一个消息给某个窗口,在对方处理完消息之前,这个函数不返回。

当对方处理完毕以后,该函数才把消息处理函数所返回的值返回给调用者。

B. 异步

异步的概念和同步相对。

当一个异步过程调用发出后,调用者不会立刻得到结果。

实际处理这个调用的部件是在调用发出后,通过状态、通知来通知调用者,或通过回调函数处理这个调用。

C++是不是类型安全的?

答案:不是。两个不同类型的指针之间可以强制转换(用reinterpret cast)。C#是类型安全的。

main 函数执行以前,还会执行什么代码?

答案:全局对象的构造函数会在main 函数之前执行。

请说出const与#define 相比,有何优点?
答案:

const作用:定义常量、修饰函数参数、修饰函数返回值三个作用。被Const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。

1) const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。

2) 有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。

vector的reserve和capacity的区别?

答:reserve()用于让容器预留空间,避免再次内存分配;capacity() 返回在重新进行内存分配以前所能容纳的元素数量。


cpp面经(杂乱版)
http://example.com/2024/05/09/cpp面经/
Author
Yaodeer
Posted on
May 9, 2024
Licensed under