c++虚函数

    更多相关内容见http://www.cnblogs.com/mu-ye/p/7754368.html

    如前所诉,在C++语言中,当我们使用基类的引用或指针调用一个虚函数时会执行动态绑定。因为我们直到运行时才知道到底调用了哪个版本的虚函数,所以所有虚函数都必须有定义。通常情况下,如果我们不使用某个函数,则无须为该函数提供定义。但是我们必须为每一个虚函数都提供定义,而不管它是否被用到了,这是因为连编译器也无法确定到底会使用哪个虚函数。

 

关键概念:C++的多态性

    OOP的核心思想是多态性。我们把具有继承关系的多个类型称为多态类型,因为我们能使用这些类型的“多种形式”而无须在意它们的差异。引用或指针的静态类型和动态类型不同这一事实正是C++语言支持多态性的根本所在。

    当我们使用基类的引用或指针调用基类中定义的一个函数时,我们并不知道该函数真正作用的对象是什么类型,因为它可能是一个基类对象也可能是一个派生类的对象。如果该函数是虚函数,则直到运行时才会决定到底执行哪个版本,判定的依据是引用或指针所绑定的对象的真实类型。

    另一方面,对非虚函数的调用在编译时进行绑定。类似的,通过对象进行的函数(虚函数或非虚函数)调用也在编译时进行绑定。对象的类型是确定不变的,我们无论如何都不可能令对象的静态类型和动态类型不一致。因此,通过对象进行的函数调用将在编译时绑定到该对象所属类中的函数版本上。

    note:当且仅当对通过引用和指针调用虚函数时,才会在运行时解析该调用,也只有在这种情况下对象的动态类型才有可能与静态类型不同。

 

派生类中的虚函数:

    一旦某个函数被声明为虚函数,则在所有派生的类中都是虚函数。

    一个派生类函数如果覆盖了某个继承而来的虚函数,则它的形参类型必须与被它覆盖的基类函数完全一致。

    同样,派生类中虚函数的返回类型也必须与基类函数匹配。(类本身的指针或引用是例外)

 

final和override说明符:

    有时,我们在派生类中写虚函数时,如果不小心把参数列表写错了导致和基类中的不一致,这时,派生类的函数并没有覆盖基类的版本。编译器认为这是新定义的函数。调试并检查出这样的错误显然非常困难。我们可以使用override。

    如果我们使用override标记了某个函数,但该函数并没有覆盖已存在的虚函数,此时编译器报错。

    我们还能把某个函数指定为final,如果我们已经把函数定义成final了,则之后任何尝试覆盖该函数的操作都将引发错误。

 

虚函数与默认实参:

    默认实参由本次调用的静态类型决定。

    换句话说,如果我们通过基类的引用或指针调用函数,则使用基类中定义的默认实参,即使实际运行的是派生类中的函数版本也是如此。此时,传入派生类函数的将是基类函数定义的默认实参。

    如果虚函数使用默认实参,则基类和派生类中定义的默认实参最好一致。

 

回避虚函数的机制:

    某些情况下,我们希望对虚函数的调用不要进行动态绑定,而是强迫其执行虚函数的某个特定版本。使用作用域运算符可以实现这一目的。

    baseP->Quote::net_price(42);

    该代码强行调用Quote的net_price函数,而不管baseP实际指向的对象类型到底是什么。该调用将在编译时完成解析。

    note:通常情况下,只有成员函数(或友元)中的代码才需要使用作用域运算符来回避虚函数的机制。

    需要回避虚函数机制的情况:通常是当一个派生类的虚函数调用它覆盖的基类的虚函数版本时。

    warning:如果一个派生类虚函数需要调用它的基类版本,但是没有使用作用域运算符,则在运行时该调用将被解析为对派生类版本自身的调用,从而导致无限递归。

 

posted @ 2017-11-06 14:51  哲贤  阅读(269)  评论(0编辑  收藏  举报