(1)虚拟内存机制
堆是操作系统维护的一块内存,而自由存储是C++中通过new与delete动态分配和释放对象的抽象概念,堆与自由存储区并不等价
(2)C++虚函数及其指针
虚函数:实现类的多态
实现原理:虚函数表和虚函数表指针
代码的编译阶段,虚表就可以构造出来了
虚表指针:一个类只需要一个虚表,它的所有对象共用一个虚函数表
(3)smart point
原因:C++的动态内存管理:一种是忘记释放内存,会造成内存泄漏;一种是尚有指针引用内存的情况下就释放了它,就会产生引用非法内存的指针。
说明:标准库提供的两种智能指针的区别在于管理底层指针的方法不同,shared_ptr允许多个指针指向同一个对象,unique_ptr则“独占”所指向的对象。标准库还定义了一种名为weak_ptr的伴随类,它是一种弱引用,指向shared_ptr所管理的对象,这三种智能指针都定义在memory头文件中。
————————————————
shared_ptr :
提供make_shared函数:
最安全的分配和使用动态内存的方法就是调用一个名为make_shared的标准库函数,此函数在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr。头文件和share_ptr相同,在memory中
必须指定想要创建对象的类型,定义格式见下面例子:
shared_ptr p3 = make_shared(42);
shared_ptr p4 = make_shared(10,‘9’);
shared_ptr p5 = make_shared();
原理:shared_ptr都有一个关联的计数器,通常称其为引用计数,无论何时我们拷贝一个shared_ptr,计数器都会递增。当我们给shared_ptr赋予一个新值或是shared_ptr被销毁(例如一个局部的shared_ptr离开其作用域)时,计数器就会递减,一旦一个shared_ptr的计数器变为0,它就会自动释放自己所管理的对象
————————————————
Unique_ptr : 某个时刻只能有一个unique_ptr指向一个给定对象,由于一个unique_ptr拥有它指向的对象,因此unique_ptr不支持普通的拷贝或赋值操作。
unique_ptr默认使用delete释放它指向的对象,我们可以重载一个unique_ptr中默认的删除器
我们必须在尖括号中unique_ptr指向类型之后提供删除器类型。在创建或reset一个这种unique_ptr类型的对象时,必须提供一个指定类型的可调用对象删除器。
weak_ptr是一种不控制所指向对象生存期的智能指针,它指向一个由shared_ptr管理的对象,将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放,即使有weak_ptr指向对象,对象还是会被释放。
weak_ptr的操作
————————————————
scoped_ptr
scoped和weak_ptr的区别就是,给出了拷贝和赋值操作的声明并没有给出具体实现,并且将这两个操作定义成私有的,这样就保证scoped_ptr不能使用拷贝来构造新的对象也不能执行赋值操作,更加安全,但有了”++”“–”以及“*”“->”这些操作,比weak_ptr能实现更多功能。
————————————————
(4)c语言如何实现c++对象以及私有成员
实现对象:
#include <stdio.h>
typedef struct person
{
int i;
char m;
void (*func)(struct person per, int i);
}Per;
void functionTest(Per per, int i)
{
printf(“Test\n”);
}
Per
NewPerson(struct person
this)
{
this->i = 18;
this->m = ‘x’;
this->func = functionTest;
}
int main()
{
Per p;
NewPerson(&p);
p.func(p, 19);
}
实现私有化:
头文件中:
#ifndef
OBJ_H
#define
OBJ_H
typedef struct Obj Obj;
Obj* create_obj(int id,const char* name);
void release_obj(Obj* o);
int get_obj_id(const Obj* o);
#endif
.c文件
定义Obj, 实现Obj的接口
.c main 文件
测试接口
(5)C++多态的实现
多态 :通过基类的指针或者引用在运行时实际动态绑定对象,多态是面向对象编程的核心,
1.主要通过virtual 函数实现
2.自己的虚表存放在.data段中
1) 每个父类都有自己的虚表。
2) 子类的成员函数被放到了第一个父类的表中。
3) 内存布局中,其父类布局依次按声明顺序排列。
4) 每个父类的虚表中的函数都被overwrite成了子类函数。这样做就是为了解决不同的父类类型的指针指向同一个子类实例,而能够调用到实际的函数。
(6)new和malloc的区别以及底层实现原理
区别:
1)New/delete 是c++运算符,malloc/free是c库函数;
(2)new内置了sizeof,自动计算需要的空间,malloc需手动计算字节数;
(3)new是类型安全的,其内部含有类型转换,类型检查,其自带构造功能,可返回构造的对象的指针;malloc返回void指针,需强制类型转换,不安全;
(4)new 对应delete,分别对应分配内存,构造对象,析构对象,释放内存的功能,malloc与free直接分配回收内存;
(5)malloc与free需要库文件支持,new与delete不需要。
—————————————
底层实现原理:
底层做的工作:
1.new T类型
(1)调用operator new(sizeof(T)),该函数的函数原型为void* operator new(size_t size)。
(2)调用operator new中的malloc(set_new_handle),如果申请成功,返回;申请失败(可能原因是内存空间不足),采取应对措施set_new_handler,如果应对措施没有,抛出一个异常。
(3)调用一个构造函数。构造函数显示给出,编译器自动合成。
2.delete p
(1)调用一个析构函数。
(2)调用operator delete,释放空间地址。
(3)调用free函数。
————————————————
(7)STL中的vector怎么扩容
不同的编译器实现的扩容方式不一样,VS2015中以1.5倍扩容,GCC以2倍扩容
(8)虚函数指针的初始化过程
无继承时:
1、分配内存
2、初始化列表之前赋值虚表指针
3、列表初始化
4、执行构造函数体
有继承时:
1、分配内存
2、基类构造过程(按照无继承来)
3、初始化子类虚表指针
4、子类列表初始化
5、执行子类构造函数体
虚表指针赋值应该在初始化列表之前:这是为了防止在初始化列表出现调用虚函数的情况!!!
(9)c++11原子变量介绍
表示多个线程访问同一个全局变量,确保同一时间内只有一个线程对临界区的访问
(10)C++11的特性
1)类型说明符 auto, auto变量必须要初始化
2)类型说明符decltype decltype(i) a (I的类型) decltype((I)) a (I引用的类型)
3)基于范围的for循环
4)扩展的sizeof
5)虚函数的override和final指示符
•override,表示函数应当重写基类中的虚函数(VS2010目前支持)。
•final,表示派生类不应当重写这个虚函数(VS2010目前不支持)。
6)noexcept
不抛异常
7)lambda表达式
(10)怎么理解重载与重写
1 成员函数重载特征:
a 相同的范围(在同一个类中)
b 函数名字相同
c 参数不同
d virtual关键字可有可无
2 重写(覆盖)是指派生类函数覆盖基类函数,特征是:
a 不同的范围,分别位于基类和派生类中
b 函数的名字相同
c 参数相同
d 基类函数必须有virtual关键字
3 重定义(隐藏)是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
a 如果派生类的函数和基类的函数同名,但是参数不同,此时,不管有无virtual,基类的函数被隐藏。
b 如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有vitual关键字,此时,基类的函数被隐藏。否则就是重写了。
————————————————
(11)怎么理解c++中的static关键字
- static静态数据成员属于整个类所有,类的所有对象共同维护。
- static静态函数成员也属于整个类,一般用于调用静态数据成员,不能直接访问非static成员(要指定类才行)
(12)vector list deque
使用区别:
(1)如果你需要高效的随即存取,而不在乎插入和删除的效率,使用vector
(2)如果你需要大量的插入和删除,而不关心随机存取,则应使用list
(3)如果你需要随机存取,而且关心两端数据的插入和删除,则应使用deque
Vector : 动态数组,每次扩充会以原来的2倍扩张
List : 链表
(13)C++的内存分配
(14)map与set的底层实现
-
类静态变量的初始化
-
析构函数可以是虚函数?为什么
-
深拷贝与浅拷贝
-
指针常量,常量指针的区别
C++的数据结构篇:
(1)unordered_map:内部实现 hash表
优点: 因为内部实现了哈希表,因此其查找速度非常的快
缺点: 哈希表的建立比较耗费时间
适用处:对于查找问题,unordered_map会更加高效一些,因此遇到查找问题,常会考虑一下用unordered_map
(2)map内部实现RBTree