C++相关

  • Post author:
  • Post category:其他



(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关键字

  1. static静态数据成员属于整个类所有,类的所有对象共同维护。
  2. 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



版权声明:本文为jianghao1996原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。