对C++虚函数与多态的理解

派生类对象可以替代基类对向基类对象的引用初始化或赋值,此时该引用并不是派生类对象的别名,只是派生类对象中基类部分的别名,因此该引用只能访问基类中的成员,可以理解为将派生类对象转换为基类对象了.

#include <iostream>
using namespace std;
class Father
{
public:
    Father() {}
    void display()
    {
        cout<<"show in Father class"<<endl;
    }
};
class Child:public Father
{
public:
    Child() {}
    void display()
    {
        cout<<"show in Child class"<<endl;
    }
};
int main()
{
    Child c;
    Father &f=c;//f并不是c的别名,只是c中基类部分的对象别名,可以理解为将派生类对象强制转换为基类对象,那么f当然只能访问基类中的成员
    f.display();//调用的是基类中的成员函数
    
    Father* pf=&c;//基类指针指向派生类对象,这里相当于把派生类对象的指针强制转化为基类对象的指针,那么该指针肯定是只能访问到基类对象中成员了
    pf->display();//调用的还是基类中的成员函数
    system("");
}

输出结果:

那么如何做到只用基类指针就访问到派生类中的成员函数呢?那就是 本篇的主题了,使用虚函数就可以做到.

#include <iostream>
using namespace std;
class Father
{
public:
    Father() {}
    virtual void display()
    {
        cout<<"show in Father class"<<endl;
    }
};
class Child:public Father
{
public:
    Child() {}
    virtual void display()
    {
        cout<<"show in Child class"<<endl;
    }
};
int main()
{
    Child c;
    Father &f=c;//f并不是c的别名,只是c中基类部分的对象别名,可以理解为将派生类对象强制转换为基类对象,那么f当然只能访问基类中的成员,只是现在基类中的display()函数被派生类中的相应函数取代了
    f.display();//调用的是派生类中对应函数

    Father* pf=&c;//基类指针指向派生类对象,这里相当于把派生类对象的指针强制转化为基类对象的指针,那么该指针肯定是只能访问到基类对象中成员了,只是现在基类中的display()函数被派生类中的相应函数取代了
    pf->display();//调用的还是派生类中的对应函数
    system("");
}

这里我指在display函数前加上了virtual关键字,使该函数变成了虚函数,来看结果:

可以看到这次调用的就是派生类中函数了,为什么呢?虚函数为什么会有这个效果呢?

原因就是基类中display被声明为虚函数,在声明派生类时被重载,这个时候派生类中的同名函数display函数就取代了基类中的那个虚函数。所以即使Father* pf=&c;还是把派生类对象指针强制转化为基类对象指针,但是pf->display();访问的那个display函数却是派生类中的对应函数。

这就是用基类指针访问派生类中成员的原理。那么如果该基类有多个派生类,我们只要用一个基类指针就可以访问到所有派生类中在继承基类时重载的虚函数了,只要给该指针赋值相应派生类对象的地址即可,是不是很美妙呢?而这也成就了C++的动态多态性!

所谓动态多态性,就是指在程序运行阶段才确定关联关系。例如单看pf->display()这句是无法知道到底调用了哪个类中display()函数,只有在运行阶段,才知道pf指针指向了谁,才确定是调用哪一个,这种动态关联因为是在编译后的运行阶段进行的,所以又称为滞后关联。

跟动态多态性对应的就是静态多态性了,通过函数重载和通过对象名调用虚函数,在编译时就可以确定其调用的虚函数是属于哪一个类的。因为在函数运行前进行关联,所以又称为早期关联。

猜你喜欢

转载自blog.csdn.net/qq_30483585/article/details/80647578