抽象类为什么不能被实例化?

2023-09-06 12:50:13 浏览数 (1)

首先,语法上,抽象类不能被实例化,这是语法规定。强制实例化一个抽象类的代码,编译器会报错。

其次,从继承和多态思想的角度而言,抽象基类的目的是建立一个公共接口,建立公共接口的唯一原因是它能对于每个不同的子类有不同的表示。它建立一个基本的格式,用来确定什么是对于所有派生类是公共的——除此之外,别无用途。抽象基类仅仅表示接口,不表示特例实现,因此,实例化一个抽象类对象,总是没有意义的。

第三,从编译器设计的实现上来看,如果想要禁止用户实例化抽象类,可以在抽象类的所有虚函数里,打印出错的信息,以提示用户不能实例化抽象基类。但是这种方法只有到运行时才能获得出错信息,并且要求程序员进行可靠且详尽的测试,并不能禁止程序员实例化抽象基类。最好是在编译时就能发现这个问题。

实现上,通过在虚函数结尾处加上"=0"来声明纯虚函数:

代码语言:javascript复制
virtual void func() = 0;

虚函数与多态的原理在于,带有虚函数的类及其派生类,其对象内部会有一个指向VTABLE的指针,即vptr。VTABLE,即虚表,其中会填写好每个虚函数的地址:如果派生类覆写(override)了某个虚函数,那么该虚函数的所占据的表项将填为派生类覆写的虚函数的地址。否则,该表项填写基类该虚函数的地址。通过这样的机制,可以保证以指针或引用方式(即地址)访问派生类对象时,总是会通过vptr所指向的虚表中某个特定索引位置上的函数地址,调用实际指针或引用所指的派生类对象定义的虚函数实现。

其中,”填写“这个动作,实际上是编译器来完成,当构建派生类对象时(即构造函数),编译器会在VTABLE中放置特定类的虚函数的地址。

如果将基类的虚函数声明为纯虚函数,即:

代码语言:javascript复制
virtual void func() = 0;

这样做,等于告诉编译器,在VTABLE中为函数保留一个位置,但在这个特定位置中不放地址(函数地址)。因此,只要有一个函数在类中被声明为纯虚函数,则VTABLE就是不完全的

如果一个类的VTABLE是不完全的,当某人试图创建这个类的对象时,编译器做什么呢?它不能安全地创建一个纯抽象类的对象。

0 人点赞