c++ 函数指针_虚函数_虚函数表_纯虚函数
函数指针
1: 函数调用: 准备好参数后,把指令指针拨动到函数开始的位置;
2: 函数的开始的指令对应一个代码段上的内存地址,这个内存地址在C/C++
里面是函数的名字
3: 除了普通数据类型的指针,还可以定义函数指针; void (*ptr)(int value);
返回值为void
,参数为int
的类型的函数的指针,可以存放函数所在的地址; ptr
= 函数的名字;
4: 使用变量可以访问得到这个地址,从而可以使用函数指针来调用函数;
5: typedef
定义一个函数指针的类型, 定义一种类型,专门用来存放这种类型的函数地址;
- 当函数调用的时候,要把指令指针拨动到函数开始的地方;
- 每个函数都对应开始的内存地址;
- c语言函数的名称就是这个函数代码指令的起始地址;
- 函数编译–>指令在代码段上的起始地址;
- 调用函数就是让我们的指令指针,跳转到起始地址;
- 函数的名字->就是地址;可以用指针变量来存放它;
- 怎么样定义一个函数指针呢?变量用来存放这种类型的函数地址
- 每一次这样定义函数指针,有点不方便;
- 使用
typedef
创造了一种类型FUNC_PRT
是一个void (int)
函数指针类型
虚函数
1: 虚函数: virtua
l 修饰的成员函数;
2: 虚函数表:
1>每个类都有一个全局唯一的虚函数表,保存了这个类里面每个虚函数对应的函数地址;
2>每个类的实例都会有一个虚函数表的指针,指向这个虚函数表;
3>调用虚函数的时候,首先从实例对象里面的虚函数表的指针,获得虚函数表,然后找到对应函数的地址,然后调用;
4>虚函数的调用性能要比普通的成员函数要差;
-
virtual
定义函数我们把它叫做虚函数 - 虚函数表:
- 每一个类在代码段上,都有全局唯一的虚函数表;
- 这个表里面存放的就是每个虚函数所在地址;
- 编译器在编译的时候就会在代码段上生成一个虚函数表;
- 每一个虚函数在这个表里面就会有一个偏移;
- 虚函数表是的是它在虚函数表的偏移;
- 全局唯一的,每一个类只要有虚函数都有一个这样的表;
- 每个类的实例,如果类里面有虚函数,那么实例里面会有一个指针,指向它的虚函数表;
- 调用虚函数:
- 1> 获取实例的虚函数表指针,就获得类的虚函数表;
- 2> 函数名字,就能够对应到虚函数表里面的偏移;
- 3> 查虚函数表,找到这个代码地址,准备好参数后,跳转过去;
- 4> 虚函数调用的性能开销视察表过程,没有普通函数调用那么快,那么高;
虚函数表与继承
1: 当子类继承父类的时候,子类的虚函数表,编译器首先会复制父类的虚函数表;
2: 如果子类有自己的新的虚函数,就加到虚函数表的后面;
3: 如果子类重载了父亲的虚函数,那么就会把原来父亲虚函数位置的地址改成现在重载的地址;
- 虚函数表继承:
- 1> 拷贝过来父类的虚函数表;
- 2> 如果有新的虚函数,那么就加到后面;
- 3> 如果重载了父类的虚函数,那么在虚函数表里面把原来父类的函数更新成你重载的函数
基类指针指向子类实例
1: 定义一个基类指针 = new 子类实例
2: 基类指针调用普通的成员函数:
1>只会在基类里面搜索;
2> 基类里面有的函数,子类重载了,使用基类的指针来调用这个函数,还是基类的函数;
3: 如果基类里面有个虚函数:
1>会去到子类的虚函数表里面去找对应的偏移;
2>如果子类重载了这个虚函数,那么调用的就是子类的函数;
- 我们知道子类is-a基类;
- 基类指针指向子类实例:
- 1> 使用这个指针来调用普通的的函数,只能访问到基类的方法和成员;
- 2> 如果使用指针来访问普通的成员函数,访问的是基类的成员函数
- 3> 如果 子类重载父类虚方法,指向的是子类的成员函数
-
address
会找到对应的,虚函数表的指针–>man
; -
test_func
在homan
类里面偏移是1; -
man
表,偏移为1的函数被子类重载了,所以更新成了子类重载后的函数man::test_func(){}
-
纯虚函数 (抽象接口)
1: 纯虚函数:定义virtual 返回值 函数名字(参数) = 0;
2: 特点:
1>有函数没有实现,故这个类不能实例化;
2>用途:强制子类要重载这个接口,否者不能使用;
3: 多用于抽象必须实现的接口;
- 纯虚函数:
- 1> 函数没有实现 = 0;
- 2> 有纯虚函数的类,是叫做抽象类,不能够直接实例化;
- 3> 因为还有一个函数没有实现,所以不能实例化!要实现实例化除非实现接口
- 4> 抽象接口,强制要实例化的子类必须要实现这个方法;
- 1> 函数没有实现 = 0;
总结
1: 掌握函数指针;
2: 掌握虚函数与虚函数表,以及虚函数调用过程;
3: 掌握虚函数表的继承;
4: 掌握基类的指针指向子类的实例,调用普通函数与虚函数;
5: 掌握纯虚函数的用途;