0%

面试八股

施工中 To be continue…

面试八股

23 春招过程中的一些准备 -> 找实习过程中的一些准备

OOP与类

通过定义一个类(class)来定义自己的一个数据结构
一个类定义了一个类型,以及与其关联的一组操作

类的基本思想是数据抽象(data abstraction)和封装(encapsulation)

OOP:概述

OOP(objected-oriented programming)面向对象程序设计的核心思想是数据抽象、继承和动态绑定
使用数据抽象将类的接口与实现分离;使用继承,可以定义相似的类型并对其相似关系建模;使用动态绑定,可以在一定程度上忽略相似类型的区别,以统一的方式使用它们的对象

OOP 的三大特性分别是封装性、继承性、多态性

继承

派生类(子类)继承基类(父类),允许在保持原有类特性的基础上进行扩展,增加功能,通过继承机制,可以利用已有的数据类型来定义新的数据类型

封装

把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏

public 成员:可以被任意实体访问
protected 成员:只允许被子类及本类的成员函数访问
private 成员:只允许被本类的成员函数、友元类或友元函数访问

多态

可以将多态定义为消息以多种形式显示的能力

C++ 多态分类
重载多态(Ad-hoc Polymorphism,编译期):函数重载、运算符重载
子类型多态(Subtype Polymorphism,运行期):虚函数
参数多态性(Parametric Polymorphism,编译期):类模板、函数模板
强制多态(Coercion Polymorphism,编译期/运行期):基本类型转换、自定义类型转换

静态多态(编译期/早绑定)
函数重载
动态多态(运行期期/晚绑定)
虚函数:用 virtual 修饰成员函数,使其成为虚函数
动态绑定:当使用基类的引用或指针调用一个虚函数时将发生动态绑定

重载与重写

重载:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可
重写:在子类中可以根据需要对从父类中继承来的方法进行改造,也称为方法的重置、覆盖。在程序执行时,子类的方法将覆盖父类的方法

C++语言特性

深拷贝与浅拷贝

浅拷贝(默认拷贝函数):将原对象或原数组的引用直接赋给新对象,新数组,新对象/新数组只是原对象的一个引用
深拷贝:创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,是“值”而不是引用
深拷贝会在堆内存中另外申请空间来储存数据,从而解决了指针悬挂问题。当数据成员中有指针时,必须要用深拷贝

指针与引用的区别

指针是一个变量,存储的是地址,指向内存单元
引用是变量的别名,跟原始变量是同一块内存
引用不可以为空,但指针可以为空
指针可以不初始化,引用必须初始化
引用不可以改变指向,但是指针可以改变指向
引用的大小是所指向的变量的大小,指针是指针本身的大小,4 / 8 个字节
引用比指针更安全。由于不存在空引用,并且引用一旦被初始化为指向一个对象,它就不能被改变为另一个对象的引用,因此引用很安全。对于指针来说,它可以随时指向别的对象,并且可以不被初始化,或为 NULL,所以不安全

将引用作为函数参数(传引用与传值)

使用引用传参,不会创建拷贝,可以提升效率节省空间
在函数中对该变量进行修改,函数返回后修改依然存在,与值传递不同
C++ 的标准不允许复制构造函数传值参数,最好是传引用

宏定义与 const 常量

宏定义相当于字符替换,预处理器处理,无类型安全检查,不分配内存,存储在代码段,可通过 #undef 取消

const 常量是一个常量的声明,在编译器处理,有类型安全检查,要分配内存,存储在数据段,不可取消

this 指针

this 指针是一个隐含于每一个非静态成员函数中的特殊指针。它指向调用该成员函数的那个对象
不能取得 this 指针的地址,不能给 this 指针赋值,在被 const 修饰的成员函数里,不能修改 this 指针所指向的对象

inline 内联函数

相当于宏,但有类型检查,编译器一般不内联包含循环、递归、switch 等复杂操作的内联函数,在类声明中定义的函数,除了虚函数的其他函数都会自动隐式地当成内联函数

虚函数(virtual)可以是内联函数(inline)吗
虚函数可以是内联函数,内联是可以修饰虚函数的,但是当虚函数表现多态性的时候不能内联

虚函数

静态函数(static)不能是虚函数
构造函数不能是虚函数(因为在调用构造函数时,虚表指针并没有在对象的内存空间中,必须要构造函数调用完成后才会形成虚表指针)
析构函数可以是虚函数
虚析构函数是为了解决基类的指针指向派生类对象,并用基类的指针删除派生类对象

虚函数与纯虚函数

虚函数在子类里面可以不重写;但纯虚函数必须在子类实现才可以实例化子类
带纯虚函数的类叫抽象类,这种类不能直接生成对象,而只有被继承,并重写其虚函数后,才能使用

虚函数指针、虚函数表

虚函数表指针:在含有虚函数类的对象中,指向虚函数表,在运行时确定。
虚函数表:在程序只读数据段(.rodata section,见:目标文件存储结构),存放虚函数指针,如果派生类实现了基类的某个虚函数,则在虚表中覆盖原本基类的那个虚函数指针,在编译时根据类的声明创建。

malloc free 与 new delete

malloc:申请指定字节数的内存。申请到的内存中的初始值不确定
free:释放内存空间
new / new[]:先底层调用 malloc 分配了内存,然后调用构造函数(创建对象)
delete/delete[]:先调用析构函数(清理资源),然后底层调用 free 释放空间
new 在申请内存时会自动计算所需字节数,而 malloc 则需我们自己输入申请内存空间的字节数。

构造函数初始值列表与赋值之间的差异

初始值列表直接初始化数据成员,后者先初始化再赋值
构造函数的初始值有时必不可少,如果成员变量是 const、引用,或者属于某种未提供默认构造函数的类类型,我们必须通过构造函数初始值列表为这些成员提供初值
建议使用构造函数初始值列表,避免编译错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class ConstRef {
public:
ConstRef(int ii);
private:
int i;
const int ci;
int& ri;
};

// 错误:ci 和 ri 必须被初始化
ConstRef::ConstRef(int ii)
{
i = ii;
ci = ii; // 错误,不能给 const 赋值
ri = i; // 错误,ri 没被初始化
}

// 正确:显式地初始化引用和 const 成员
ConstRef::ConstRef(int ii) : i(ii), ci(ii), ri(i) { }

智能指针

shared_ptr | unique_ptr | weak_ptr | auto_ptr(被 C++11 弃用)

强制类型转换运算符

static_cast | dynamic_cast | const_cast | reinterpret_cast | bad_cast

运行时类型信息 (RTTI)

dynamic_cast | typeid | type_info

Lambda 表达式

移动语义

右值引用

数据结构

数组与链表的区别

计算机网络

计算机系统

内存对齐

设计模式

概述

设计模式三原则:单一职责原则,开放封闭原则,依赖倒转原则
设计模式分类:创建型模式、结构型模式、行为模式

单例

单例模式是一种创建型设计模式,让你能够保证一个类只有一个实例,并为该实例提供一个全局访问节点,单例模式同时解决了两个问题,所以违反了单一职责原则

构造函数私有化,在类内部创建一个唯一的私有的静态对象,并提供一个静态函数用于得到这个静态的单例对象
拷贝构造函数私有化或者禁用
拷贝赋值操作符重载函数私有化或者禁用

工厂

工厂方法模式 | 简单工厂模式 | 抽象工厂模式

工厂方法模式是一种创建型设计模式,其在父类中提供一个创建对象的方法,允许子类决定实例化对象的类型,其使用特殊的工厂方法代替对于对象构造函数的直接调用
简单工厂模式与工厂模式的不同在于其只使用一个工厂类来生产许多不同的产品对象
抽象工厂模式是一种创建型设计模式,它能创建一系列相关的对象,而无需指定其具体类