文章目录
项目中遇到的困难以及如何解决的
除了硬件方面的有没有涉及语言软件方面的
对多态的理解
多态分为静态多态和动态多态,静态多态通过函数重载以及运算符重载实现。重载允许一个函数名或操作符有多个定义,编译时,编译器会根据函数参数以及上下文选择正确的定义
动态多态通过虚函数以及继承实现,在运行阶段根据对象的类进行调用。
多态的实现
多态的实现通常依赖于虚函数,在基类中声明虚函数,并在子类中进行重写。通过基类指针或引用调用虚函数时,将根据对象的实际类型调用子类或派生类的函数。
操作符重载的原理
通过类的成员函数重载
bool operator==(const person& ps)
{
if (this->age == ps.age)
{
return true;
}
return false;
}
通过非成员函数重载
bool operator==(person const& p1 ,person const& p2)
{
if (p1.age == p2.age)
{
return true;
}
else
{
return false;
}
}
操作符左值需显式指定。
左操作数为类的对象才能使用类的重载操作符成员函数,
= [] () ->等运算符必须定义为类的成员函数
虚函数的定义和实现
虚函数是在基类中使用virtual关键字声明的成员函数,允许在派生类中对虚函数进行重写,重写时虚函数的函数名、返回值、参数列表应与基类保持一致。
特例:
协变-子类中虚函数的返回变量为子类指针
析构函数的重写,目测不同,析构函数的名称统一处理成destructor
纯虚函数
通过在虚函数后加上=0实现,纯虚函数必须进行重写。
虚函数表的认识
虚函数表是在编译期间生成的,虚函数表指针在对象的构造函数中完成,创建对象时会生成虚函数表指针指向虚函数表。
派生类对象在内存中由两部分组成,一部分是基类继承下来的成员,虚函数表指针存储于该部分,另一部分是派生类自己的成员
虚函数表与普通函数一样都存储于代码段,虚表也存储在代码段
存储位置
代码段
与子类、父类的关系
在编译时子类首先会拷贝父类的虚函数表,若子类中的虚函数发生的重写,则将新的虚函数地址对原地址进行覆盖。子类自己新增加的虚函数会按声明顺序增加到虚函数表的最后。
一个类有几个虚函数表
一个类只有一个虚函数表
同一个类不同对象的虚函数表有无区别
没有区别,指向的是同一个虚函数表
内存空间划分
堆栈数据段统一划分,代码段包含有只读常量以及可执行代码
.data属于数据段存储
const修饰全局变量时存放在只读区、文字常量区
修饰局部变量时存储在栈区,(可以通过地址读写),无法作为左值或作为右值赋值给变量
常量区及代码区的区别
常量可存储在.rodata或.data中,.data中的常量无法通过变量名修改其值,但可以通过内存访问修改,两者均属于只读段,编译的代码存储于.text,只读常量(全局const或字符串常量(用于打印的))存储于.rodata,无法通过地址修改,虚函数表存储于.rodata,初始化给字符串变量的字符串常量存储在.data栈区
菱形继承是什么
const关键字的理解
修饰后无法通过变量名修改
常量指针 const int *ptr
表示指针指向的内容时常量无法修改,都指针本身可以指向其他变量
指针常量 int * const ptr
表示指针无法指向其他内容,但指向的值可以修改。
即const修饰的变量无法改变。
const修饰函数返回值时需要保证函数返回值赋值给同类型的const变量。
修饰类的成员函数会造成什么影响及作用
const修饰成员函数时无法在函数内对其他成员变量进行修改
const修饰的对象只能调用const成员函数
const修饰的成员变量须在类的构造函数中以参数列表的形式进行赋值(以及引用类型成员变量和类成员变量)。
修饰返回值与普通函数一致。
修饰形参与普通函数一致。
同名函数的使用
同名函数和操作符重载函数在编译时都涉及到三个阶段
重载候选函数集合构建阶段:选择所有与函数调用名称相匹配的候选函数,函数名相同但参数列表不同。编译器会扫描当前作用域下的所有函数,根据函数名构建出合适的候选函数集合
**函数模板实例化阶段:**重载解析时发现有函数模板作为候选函数,编译器会将模板函数实例化并加入候选函数集合,
**重载决议阶段:**会选择最匹配的函数进行调用。
同名函数是如何实现的
类中的同名函数与其他普通函数的区别(且数据类型一致) 有什么本质区别
在调用函数时会由重载决议进行判断,两者若作用域一致则会同时进入候选函数集合,然后由重载决议根据上下文决定调用哪个函数。
调用类的成员函数需要通过该类的实例对象调用,若该成员函数是静态成员函数则可以通过类名::调用,这都会作为重载决议的判断依据。
static关键字的理解
数据的作用域
静态关键字定义的函数或变量仅能在当前作用域使用,且在程序结束时才销毁
如函数内的静态变量仅能在函数内使用且在程序结束时才被销毁
文件内函数外的静态变量仅能在当前文件使用
类内定义的静态成员变量或静态成员函数在该类所有均可以使用,并且访问的是同一个静态成员变量
外部定义有无static的区别
作用域不一样
静态成员函数与非静态成员函数
静态成员函数可以直接引用静态成员变量,不需要添加类名或对象名。(同一个类所有对象的静态成员变量一样)
静态成员函数无法访问类对象的非静态成员变量以及非静态成员函数,只能调用其他静态成员函数。
静态成员函数无法使用this指针,减少了内存开销,速度少许增加
非静态成员函数可以访问类内所有成员变量或成员函数
普通静态函数
仅能在声明该函数的文件中可用,不能被其他文件使用
类中的静态成员变量
该类所有对象均使用该成员变量,普通成员变量在构造对象时会发生改变。
静态成员变量存储在全局数据区,需要在类外部定义,在类定义时就需要分配空间
对智能指针的理解
智能指针作为c++11的新特性,极大的方便了开发人员对指针的管理。
避免了野指针、重复释放以及内存泄漏的问题。
主要分为shared_ptr\unique_ptr以及weak_ptr三种
为什么没有使用过智能指针
怎么实现的
shared_ptr可以实现对内存空间的自动释放,通过维护一个可以根据内存空间占用指针个数的变量,实现对内存空间的自动释放,当内存空间被占用数为0时(即无法再次通过变量名访问该内存空间,则自动释放该片内存。
存在循环引用的问题,导致无法正常销毁内存空间
使用weak_ptr,该类指针为对内存空间的弱引用,不会引起计数变量的增减,但可以通过该指针访问相应的内存空间,并判断该内存空间的占用情况。
unique_ptr保证了该片内存空间仅被占用一次,无法创建多个指针指向该内存空间。
智能指针的分类及区别
使用过哪些容器
具体的使用场景
vector queue stack map set pair
vector(点云数据保存处理
queue(滑动窗口求解滑动平均值进行滤波
stack(实际项目中还没用到过,做算法题有用到
map(实际项目中还没用到过,做算法题有用到
set(实际项目中还没用到过,做算法题有用到
pair(生成数据对
各个容器有哪些区别
map和set具体使用
map作为一个容器存储的是pair,通过红黑树实现,具有有序性
set是一个集合容器,会对数据进行去重,
unordered_map以及unordered_set的区别及使用场景
两者均是无序的容器,在不需要对元素进行遍历,只需要查找时可以通过unodered提高查找效率。
两者基于hash表实现。
引用与指针的区别
指针存在空指针,引用不存在,必须指向一个实例化的对象
指针可以随时初始化,引用在定义时需初始化
指针可以改变指针指向的变量,引用不可以改变