抽象类

1. 纯虚函数

1)概念

​ 在虚函数的声明结尾处添加“=0”,这种虚函数被称为纯虚函数,是一个没有实现只有声明的函数

2)作用

​ 为了让类具有抽象类的功能,让继承自抽象类的子类都具有虚表以及虚表指针

image-20230226192954776

3)纯虚函数在虚表中的处理

​ 因为纯虚函数没有实现代码,所以没有首地址。编译器为了防止误调用纯虚函数,将虚表中保存的纯虚函数的首地址项替换成函数__purecall,用于结束程序

2. 抽象类

不能实例化(且不可作为参数、返回值、类型转换)(声明抽象类指针或引用,指向子类来体现多态)

1)概念

​ 含有纯虚函数的类

2)抽象类的特征

​ 一旦在虚表中发现函数地址为__purecall(GCC编译器函数名称为___cxa_pure_virtual)函数的地址时,可以高度怀疑此虚表对应的类是一个抽象类

​ 当抽象类中定义了多个纯虚函数时,虚表中将保存相同的函数指针

image-20230226193255783

c++代码示例:

#include <stdio.h> 
class AbstractBase  {
  public:
  AbstractBase()  {
    printf("AbstractBase()"); 
  }
  virtual void show() = 0; //定义纯虚函数 
};

class VirtualChild : public AbstractBase  {     //定义继承抽象类的子类
public:
  virtual void show() {                         //实现纯虚函数
    printf("抽象类分析\n"); 
  }
};
int main(int argc, char* argv[]) { 
  VirtualChild obj;
  obj.show(); 
  return 0; 
}

vs_x86汇编标识:

00401020  push    ebp                           ;抽象类构造函数
00401021  mov     ebp, esp
00401023  push    ecx
00401024  mov     [ebp-4], ecx
00401027  mov     eax, [ebp-4]

0040102A  mov     dword ptr [eax], offset ??_7AbstractBase@@6B@ ;设置抽象类虚表指针
00401030  push    offset aAbstractbase ; "AbstractBase()"
00401035  call    sub_4010D0           ;调用printf函数
0040103A  add     esp, 4
0040103D  mov     eax, [ebp-4]
00401040  mov     esp, ebp
00401042  pop     ebp
00401043  retn

;抽象类AbstractBase中虚表信息的第一项所指向的函数首地址 
0000:00401C3B  push    esi                      ;__purecall函数
0000:00401C3C  mov     esi, dword_419C6C
0000:00401C42  test    esi, esi
0000:00401C44  jz      short loc_401C50
0000:00401C46  mov     ecx, esi
0000:00401C48  call    ds:___guard_check_icall_fptr
0000:00401C4E  call    esi ; dword_419C6C
0000:00401C50  call    _abort                   ;结束程序
posted @ 2023-02-26 19:35  修竹Kirakira  阅读(18)  评论(0编辑  收藏  举报