虚函数是指针还是c语言(C语言中的虚函数)

上一节较为详细的讨论了C 语言中基类被派生类继承过程中的内存模型,尤其较为详细的分析了虚函数及其虚表、虚表指针在内存中是如何分布,如何存储的,这对于理解C 语言中的“动态绑定”是极有帮助的。

虚函数是指针还是c语言(C语言中的虚函数)(1)

对于理解C 语言中的“动态绑定”是极有帮助的

正如之前两篇文章所讨论的,C 语言中虚函数的“动态绑定”能为多态的实现带来极大的便利——“动态绑定”机制是在程序运行时根据指针所指向对象的类型(而不是指针本身类型)决定被调用的成员函数,因此在C 语言程序开发中,使用基类指针就可以调用其所有派生类的成员函数。可见,C 语言中的虚函数其实就是为了提升程序员开发的便利设计的。事实上,为了充分利用这种设计带来的便利性,C 语言中还有着“纯虚函数”的概念。

纯虚函数与抽象类

所谓“纯虚函数”,其实就是没有具体实现的虚函数,通常定义在基类中提供类似于“接口”的功能。因为没有具体实现,也即该函数没有具体功能,拥有纯虚函数的基类通常被称作“抽象类”,所以抽象类无法实例化对象,一般只能作为基类被其他派生类继承使用。继承了抽象基类的派生类必须重写所有的纯虚函数,也即为类提供具体的功能,才能实例化对象使用。

在C 语言中,只要某个类有纯虚函数,或者继承了抽象类而没有重写所有纯虚函数,那么该类就是“抽象类”,无法实例化对象。

在C 语言中,在类中定义纯虚函数是非常简单的,只需在函数后使用=0就可以了,例如下面这段示例代码:

class Base { public: void f1(){...} // 非虚函数 virtual void f2(){...} // 虚函数,但是不纯 virtual void f3() = 0; // 纯虚函数 }; Base b; // 非法,纯虚函数 f3() 没有具体实现(功能)

上面的 Base 就是一个抽象类(因为它有一个纯虚函数 f3()),所以无法直接使用 Base 实例化对象。正如前文所说,抽象类通常是作为基类使用的,例如下面这段C 语言代码示例:

class Derived : public Base { // 没有 f1(),没问题 // 没有 f2(),没问题 void f3(){...} // 重写 f3() }; Derived d; // 合法, Derived::f3 重写了 Base::f3

Derived 类继承了抽象基类 Base,并且重写了纯虚函数 Base::f3(),因此 Derived 类可以实例化对象 d 使用。注意到派生类 Derived 重写 f3() 时并未显式的使用 virtual 关键字,这是没有问题的,只要保证函数名、参数、返回值都与基类 Base 中的纯虚函数一致,编译器会自动将其识别为虚函数的。

因为派生类 Derived 重写了基类 Base 中的纯虚函数,因此它不再是抽象类,其他继承 Derived 的派生类也不再是抽象类,除非这些派生类定义了自己的纯虚函数。

虚函数是指针还是c语言(C语言中的虚函数)(2)

纯虚函数也可以有功能

纯虚函数也可以有功能

基类中的纯虚函数也可以像其他普通函数那样提供一些通用的功能,例如:

void Base::f3(){ cout<< "ok\n"; }

但是要注意,即使纯虚函数 f3() 有自己的功能,基类 Base 仍然是抽象类,还是不能够实例化对象,它的派生类必须重写 f3(),否则该派生类也是抽象类,只不过派生类在重写 f3() 时,可以调用 Base::f3(),例如下面这段C 语言代码示例:

void Derived::f3() { ... Base::f3(); }

纯虚函数非常有用

纯虚函数可以提供抽象类的功能,抽象类则通常提供统一接口的功能,强迫继承它的派生类各自实现符合自己特点的具体功能,并且一定要有这样的功能,这对于设计和架构非常有用。例如,设计师设计了一个汉语翻译程序,他定义了一个基类,该基类中有两个纯虚函数:

class Base { public: virtual string translate_to(string raw) = 0; virtual string translate_from(string raw) = 0; void help() { ... }; };

其中 translate_to() 函数负责将其他外语翻译为汉语,translate_from() 函数负责将汉语翻译为其他外语,因为暂时还不知道具体要实现哪种外语与汉语的翻译,因此这两个函数都是纯虚函数。在接下来的C 语言程序开发中,各种子外语都需要继承 Base,也即必须提供各自的翻译实现,设计师的基本功能要求就成了必须完成的任务。从上面的这个例子可以看出,借助于C 语言的纯虚函数机制,设计师无需再提供详细的功能实现,仅需设计出基本功能要求就可以了。至于非虚函数 Base::help() 函数则可以提供通用的功能,比如输出此程序的帮助信息。

小结

稍稍思考下,应该能够发现C 语言中的纯虚函数其实提供了一种“强制”功能——纯虚函数必须被具体实现,才能够实例化对象使用,从文章末尾的例子能够看出这非常有用。这么看来,C 语言中的纯虚函数倒有些类似于“必须实现的接口”了,的确如此,实际上在实际的C 语言程序开发中,如果某个抽象类没有成员变量,它的所有函数均为纯虚函数,那么它就是一组函数接口。


虚函数是指针还是c语言(C语言中的虚函数)(3)

点个关注吧

欢迎在评论区一起讨论,质疑。文章都是手打原创,每天最浅显的介绍C语言、linux等嵌入式开发,喜欢我的文章就关注一波吧,可以看到最新更新和之前的文章哦。

未经许可,禁止转载。

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页