指针和引用的区别

指针定义的时候不用初始化,后期也可以修改指向,占内存空间,可以有多级指针

引用定义的时候必须要初始化,后期不可以改变指向,它只是代表一个别名,不占内存,引用不能有多级引用

 

 堆和栈的区别

堆的内存空间必须要是malloc  new来申请,并且必须要用 free  delete来相应的回收内存,栈的话自己会回收

 

 new和delete是如何实现的,new 与 malloc的异同处

new底层是用malloc来实现的

如果是对象的话

1,用malloc来申请一块内存

2,然后在这块内存上调用构造函数

delete底层使用free来实现

如果是对象

1,先调用析构函数

2,干掉这块内存

 

 

C和C++的区别

C只是高级语言

C++是面向对象语言,C++多了三大特性,继承,重载,多态

 

 

 C++、Java的联系与区别,包括语言特性、垃圾回收、应用场景等(java的垃圾回收机制)

语言特性的话:c++ 有指针,多继承,强制类型转换

Java 有垃圾回收机制能够自动释放掉申请的内存,而C++是以能够操作内存著称,但是很容易带来一些错误

应用场景:c++用于底层和中间件,java用于高层

 

Struct和class的区别

struct 默认使用 public成员权限,默认使用private成员权限

 

 

 define 和const的区别(编译阶段、安全性、内存占用等)

编译阶段:define处于编译阶段直接替换,const处于运行期

安全性:define 没得类型检查,const有类型检查

内存占用:define不占用内存,const因为实质上还是一个变量所以要占用内存

 

 在C++中const和static的用法(定义,用途)

const可以修饰函数和变量,修饰类成员函数的话就代表函数里面的成员变量都不能修改

修饰指针变量的时候又分为顶层const和底层const,分别代表内容和指向不能改变

 

static三大功能

1,修饰全局变量的时候,有隐藏作用,该变量只有这个源文件能够使用,可以方便变量名重复使用

2,初始化为0

3,局部持久化,可以在函数里面修饰变量的时候,能够保存上次调用的时候的值

‘’

 C++中的const类成员函数(用法和意义)

在类成员函数的后面加上一个const

void f() const
 {
 }

 

这样代表成员函数里面的类成员不能修改,一般用于只读函数中,不想你修改值

 

计算下面几个类的大小:
class A {};: sizeof(A) = 1;        //空的,会有一个字节,避免申请两个对象公用内存
class A { virtual Fun(){} };: sizeof(A) = 4(32位机器)/8(64位机器);  //里面含有虚函数指针
class A { static int a; };: sizeof(A) = 1;      //相当于空类,因为静态存储在静态区
class A { int a; };: sizeof(A) = 4;
class A { static int a; int b; };: sizeof(A) = 4;

 

 给一个代码,求输出结果
class A
{
public:
A(int x){}
}
问:A a = 1;是否正确, 如果正确, 那么它调用了哪些函数?

转换构造函数,能够隐式转换,可以使用 explicit强制不能转

 

 C++的STL介绍(这个系列也很重要,建议侯捷老师的这方面的书籍与视频),其中包括内存管理allocator,函数,实现机理,多线程实现等

序列式容器:vector  deque  list

关联式容器:set  mulset  map  mulmap

容器配接器:queue  stack    priority_queue

内存分配器:allocator

 

C++中的重载和重写的区别:

重载:是在同一个类中,两个相同名字的函数,需要函数参数列表不相同

重写:virtual 关键字修饰的函数,子类可以再去写一遍,如果写了就使用新的这个,并且严格意义上来说这个还是属于父类,返回值,参数列表都要一样,不写就是用父类的这个

 

 介绍面向对象的三大特性,并且举例说明每一个

重载:就是同类的时候可以重载运算符,重载函数

继承:呃,不介绍了

多态:c++使用虚函数来实现多态,可以实现上行转换和下行转换

 

 多态的实现

在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。如果对象类型是派生类,就调用派生类的函数;如果对象类型是基类,就调用基类的函数

  1:用virtual关键字申明的函数叫做虚函数,虚函数肯定是类的成员函数。  

  2:存在虚函数的类都有一个一维的虚函数表叫做虚表,类的对象有一个指向虚表开始的虚指针。虚表是和类对应的,虚表指针是和对象对应的。  

 

C++虚函数相关(虚函数表,虚函数指针),虚函数的实现原理(热门,重要)

 推荐博文:https://blog.csdn.net/lyztyycode/article/details/81326699   这篇写的贼好

虚函数实现原理,其实就是两个组成,虚函数表和虚函数表指针

虚函数表是在类里面的,虚函数表指针属于创建的对象,如果对象想要使用虚函数的话,那么就要用指针找到相对应的虚函数,最开始虚函数指针都是指在虚函数表的第一个位置

然后虚函数在子类实现的时候有个名词叫做重写,意思也就是在原来位置重现了这个函数

单继承:

  没有重写:虚函数表就是按照定义的顺序来做的虚函数表,子类继承就把子类的接在了父类后面

  有重写:子类重写了父类的虚函数,那么就把父类原先那个位置的虚函数改成新的那个,这个也是为什么多态能够实现的原因,因为始终指向没有变,但是我改变了父类的虚函数表的内容

多继承:

  没有重写:会拥有多个虚函数表,自己的虚函数接在了第一个虚函数表里面

  有重写:会把所以父类虚函数表和重写同名的都改掉

 

 实现编译器处理虚函数表应该如何处理

推荐博文:https://wenku.baidu.com/view/cd87c405f12d2af90242e680.html  基本能理解原理

编译器如果检测virtual关键字,那么就会创建一个虚函数表,然后如果创建对象的话就会在前面加一个字段存储虚函数表指针

如果调用虚函数,编译器会做一个简单的替换,替换成用指针求调用虚函数

 

 

 析构函数一般写成虚函数的原因

如果基类指针向派生类对象,则删除此指针时,我们希望调用该指针指向的派生类析构函数,而派生类的析构函数又自动调用基类的析构函数,这样整个派生类的对象完全被释放。
若使用基类指针操作派生类,需要防止在析构时,只析构基类,而不析构派生类

 

构造函数为什么一般不定义为虚函数

因为调用虚函数需要虚函数指针,虚函数指针又是对象专有,但是构造函数使用虚函数的话,都没得对象就不能搞了

 

 

 构造函数或者析构函数中调用虚函数会怎样

https://www.cnblogs.com/vincently/p/4754206.html

引用里面的解释的话就是:结果会变成并没有实现多态,调用的依旧会是父类的虚函数

构造:因为基类的构造在子类构造之前,所以相当于子类的虚函数指针成员什么的都还没有建造出来,所以到基类还是基类的虚函数

析构:因为到了析构里面就默认所有成员都不存在了,就和上面一个道理了

 

 纯虚函数

纯虚函数的格式   virtual  f()=0;

代表我不实现,留给子类去实现,带有纯虚函数的类也叫抽象类,不能够实例对象出来,子类必须实现,主要解决的是多态问题,面向对象的思想

动物基类 不能实现,老虎,狮子等派生类可以给出对象,所以嘛出现了纯虚函数抽象类这个东西

 

 

静态绑定和动态绑定的介绍

动态绑定时虚函数独有的,其他都是静态绑定

摘大佬的一段话‘

(1)对象的静态类型 :对象在声明时采用的类型,是在编译期确定的。
(2)对象的动态类型:目前所指对象的类型,是在运行期决定的,对象的动态类型可以更改,但对象的静态类型无法更改。
(3)静态绑定:绑定的是对象的静态类型,其特性(如函数)依赖于对象的静态类型,发生在编译期。
(4)动态绑定:绑定的是对象的动态类型,其特性(如函数)依赖于对象的动态类型,发生在运行期。


动态绑定也就是能在运行的时候一直变化,你不能知道它哪一时刻属于什么类型,调用的哪个函数,而你一个普通函数,一眼就知道你干啥了

 

 

引用是否能实现动态绑定,为什么引用可以实现

引用和指针都是在运行期确定的,普通的是编译器

引用和指针都不改变类型,只是要一个地址和内存大小,而普通的牵扯到类型转换就不太顶

 

 深拷贝和浅拷贝的区别(举例说明深拷贝的安全性)

浅拷贝也就是把值自己拥有的值直接传给对面,但是如果成员里面有指针的时候非常不安全,因为指针的值是一个地址,相当于两个对象的指针指向同一块内存,析构的时候对同一块内存析构两下,然后造成内存泄漏,哦凉凉

深拷贝直接把它的内存都复制一份,然后指针再指向新的这块区域,对象默认拷贝和赋值都是浅拷贝

 

 

 介绍C++所有的构造函数

1,普通构造函数,就是普通那样创建

2,拷贝构造函数:利用现有对象给其他对象创建     函数传参     函数返回值 都会调用拷贝构造

3,转换构造函数:就是只有一个参数,可以有默认参数,它会你赋值一个值的时候直接转换成一个对象

 

结构体内存对齐方式和为什么要进行内存对齐?

 结构体对齐方式看你当前最大变量的内存占用字节数,然后必须是当前的倍数

因为底层读取内存块的时候,处理器只能一次读取这么大的内存块,如果变量横跨两个内存块,那么还要读取两个内存块,然后分别取出来,贼麻烦

 

 内存泄露的定义,如何检测与避免?

内存泄漏也就是使用堆内存忘记释放掉,然后到程序外面又没有指针能够指向它,内存就这样一直被占用着,无法再次使用

避免神器:智能指针

 

 

手写实现智能指针类

https://blog.csdn.net/lizhentao0707/article/details/81156384

 

智能指针是为了解决掉指针所产生的内存泄漏的问题,用来代替指针的,会自动释放掉内存

有 shared_ptr    auto_ptr    weak_ptr     unique_ptr

需要知道的是,它所实现的自动回收内存机制,是你如果要多个指针指向同一块内存区域,只能利用之前所创建的智能指针创建,利用的是拷贝构造函数和重载赋值运算来实现的

所以当两个只能指针都是拿一块内存来初始化的时候,并不会有引用计数增加的出现,这点要特别注意

手写指针还是不太熟练,明天写一个完整的出来