C++语言中的“虚函数”就像C语言中的指针,必须要弄懂的

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

C++语言中的“虚函数”就像C语言中的指针,必须要弄懂的

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

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

纯虚函数与抽象类

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

必须重写所有的纯虚函数,也即为类提供具体的功能,才能实例化对象使用。

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

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

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

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

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

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

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

C++语言中的“虚函数”就像C语言中的指针,必须要弄懂的

纯虚函数也可以有功能

纯虚函数也可以有功能

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

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

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

<code>void Derived::f3() {    ...    Base::f3();}/<code>

纯虚函数非常有用

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

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

其中 translate_to() 函数负责将其他外语翻译为汉语,translate_from() 函数负责将汉语翻译为其他外语,因为暂时还不知道具体要实现哪种外语与汉语的翻译,因此这两个函数都是纯虚函数。在接下来的C++语言程序开发中,各种子外语都需要继承 Base,也即

必须提供各自的翻译实现,设计师的基本功能要求就成了必须完成的任务。从上面的这个例子可以看出,借助于C++语言的纯虚函数机制,设计师无需再提供详细的功能实现,仅需设计出基本功能要求就可以了。至于非虚函数 Base::help() 函数则可以提供通用的功能,比如输出此程序的帮助信息。

小结

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


C++语言中的“虚函数”就像C语言中的指针,必须要弄懂的

点个关注吧

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


分享到:


相關文章: