美文网首页
c++程序员面试宝典之多态与虚函数

c++程序员面试宝典之多态与虚函数

作者: b83dcb2e8b71 | 来源:发表于2018-07-30 10:40 被阅读0次

    二十.多态与虚函数

    多态:多态按字面的意思就是多种形态。当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态,简单地说是”一个接口多种实现“

    C++提供多态的目的:可以通过基类指针对所有派生类(包括直接派生和间接派生)的成员变量和成员函数进行“全方位”的访问,尤其是成员函数。如果没有多态,我们只能访问成员变量。

    多态的分类:

    1)编译时的多态性。编译时的多态性是通过重载来实现的。

    2)运行时的多态性。运行时的多态性是通过虚成员实现的。

    下面是构成多态的条件:

    1)必须存在继承关系;

    2)继承关系中必须有同名的虚函数,并且它们是遮蔽(覆盖)关系。

    3)存在基类的指针,通过该指针调用虚函数。

    在C++中如何实现多态

    答:多态有动态多态,静态多态,函数多态和宏多态等。

      动态多态基于继承机制和虚函数来实现的。

      静态多态引入了泛型的概念。

      函数多态基于函数重载。

      宏多态基于宏替换。

    虚函数:

    作用:实现多态,基类定义虚函数,子类可以重写该函数,基类指针根据赋给它的不同的子类指针,动态调用属于子类的函数。

    底层实现原理:C++中虚函数使用虚函数表和 虚函数表指针实现。通过对象内存中的vptr找到虚函数表vtbl,接着通过vtbl找到对应虚函数的实现区域并进行调用。

    什么时候声明虚函数:

    首先看成员函数所在的类是否会作为基类,然后看成员函数在类的继承后有无可能被更改功能,如果希望更改其功能的,一般应该将它声明为虚函数。如果成员函数在类被继承后功能不需修改,或派生类用不到该函数,则不要把它声明为虚函数。

    虚函数对于多态具有决定性的作用,有虚函数才能构成多态,这节我们来重点说一下虚函数的注意事项。

    1) 只需要在虚函数的声明处加上 virtual 关键字,函数定义处可以加也可以不加。

    2) 为了方便,你可以只将基类中的函数声明为虚函数,这样所有派生类中具有遮蔽(覆盖)关系的同名函数都将自动成为虚函数。

    3) 当在基类中定义了虚函数时,如果派生类没有定义新的函数来遮蔽此函数,那么将使用基类的虚函数。

    4) 只有派生类的虚函数遮蔽基类的虚函数(函数原型相同)才能构成多态(通过基类指针访问派生类函数)。例如基类虚函数的原型为virtual void func();,派生类虚函数的原型为virtual void func(int);,那么当基类指针 p 指向派生类对象时,语句p -> func(100);将会出错,而语句p -> func();将调用基类的函数。

    5) 构造函数不能是虚函数。对于基类的构造函数,它仅仅是在派生类构造函数中被调用,这种机制不同于继承。也就是说,派生类不继承基类的构造函数,将构造函数声明为虚函数没有什么意义。

    6) 析构函数可以声明为虚函数,而且有时候必须要声明为虚函数。

    构造函数和析构函数能否声明为虚函数?

    答:构造函数不能声明为虚函数,析构函数可以声明为虚函数,而且有时是必须声明为虚函数。

    构造函数不能声明为虚函数的原因是:

    解释一:所谓虚函数就是多态情况下只执行一个。而从继承的概念来讲,总是要先构造父类对象,然后才能是子类对象。如果构造函数设为虚函数,那么当你在构造父类的构造函数时就不得不显示的调用构造。还有一个原因就是为了防错,试想如果你在子类中一不小心重写了个跟父类构造函数一样的函数,那么你的父类的构造函数将被覆盖,也即不能完成父类的构造.就会出错。

    解释二:虚函数的主要意义在于被派生类继承从而产生多态。派生类的构造函数中,编译器会加入构造基类的代码,如果基类的构造函数用到参数,则派生类在其构造函数的初始化列表中必须为基类给出参数,就是这个原因。

    析构函数设为虚函数的作用:

    在类的继承中,如果有基类指针指向派生类,那么用基类指针delete时,如果不定义成虚函数,派生类中派生的那部分无法析构。

    纯虚函数:

    纯虚函数在基类中是没有定义的,必须在子类中加以实现。

    如果基类含有一个或多个纯虚函数,那么它就属于抽象基类,不能被实例化

    虚函数与纯虚函数有什么区别

    答:

    - 虚函数:如果一个类中声明了虚函数,这个函数是实现的,他的作用是为了能让这个函数在他的子类里面能被覆盖,这样就可以实现动态多态。

    - 纯虚函数只是一个接口,是个函数的声明而已,他留在子类中实现。

    - 虚函数在子类中可以不重载

    - 纯虚函数必须在子类中实现

    - 虚函数的类用作”实现继承“,即继承接口的同时也继承了父类的实现。

    - 纯虚函数用于”介面继承“,即纯虚函数关注的是接口的统一性,实现由子类完成

    - 带纯虚函数的类叫做虚基类,这种类不能直接生成对象。

    分别简单讲述一下函数重载,函数覆盖,函数隐藏的概念与特征:

    函数重载:重载函数通常用来命名一组功能相似的函数

    1.函数要在相同的类域

    2.函数的名字要相同

    3.函数的参数列表或返回值不同

    函数覆盖(重写):覆盖是指派生类函数覆盖基类函数

    1.函数是要在不同的类域

    2.两个函数的名称相同

    3.两个函数的参数相同

    4.基类函数必须是虚函数

    函数隐藏:指派生类的函数屏蔽了与其同名的基类函数

    1.两个函数在不同的类域

    2.函数名称相同

    3.函数参数不同

    4.(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏。

    (2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual 关键字。此时,基类的函数被隐藏。

    相关文章

      网友评论

          本文标题:c++程序员面试宝典之多态与虚函数

          本文链接:https://www.haomeiwen.com/subject/geixvftx.html