c++_4:多态_2_虚函数的原理

上下类型转换与晚绑定

class Mammal
{
    public:
       virtual speak();
       move();
};
Class Dog : public Mammal
{
    void speak();
    void move();
};

int main()
{
    Mammal *pDog=new Dog;
    pDog->Move(); // 调用Mammal的方法---Mammal::move//向上类型转换
    pDog->speak();  //调用Dog的方法---Dog::speak---虚函数
}

虚函数表

转载博客: http://blog.csdn.net/haoel/article/details/1948051/

  • 父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数
  • C++的编译器应该是保证虚函数表的指针存在于对象实例中最前面的位置
class Base {
     public:
            virtual void f() { cout << "Base::f" << endl; }
            virtual void g() { cout << "Base::g" << endl; }
            virtual void h() { cout << "Base::h" << endl; }

};

Base b;

这里写图片描述

  • 函数表的最后多加了一个结点,这是虚函数表的结束结点,就像字符串的结束符“/0”一样
  • 而在Ubuntu 7.10 + Linux 2.6.22 + GCC 4.1.3下,这个值是如果1,表示还有下一个虚函数表,如果值是0,表示是最后一个虚函数表。

无继承的虚函数表

这里写图片描述

  • 在这个继承关系中,子类没有重载任何父类的函数。那么,在派生类的实例中,其虚函数表如下所示:

这里写图片描述

  • 虚函数按照其声明顺序放于表中。
  • 父类的虚函数在子类的虚函数前面。’

一般继承(有虚函数覆盖)

这里写图片描述

这里写图片描述

  • 覆盖的f()函数被放到了虚表中原来父类虚函数的位置。
  • 没有被覆盖的函数依旧。
  Base *b = new Derive();
   b->f();   //调用Derive::f()
  • b所指的内存中的虚函数表的f()的位置已经被Derive::f()函数地址所取代,于是在实际调用发生时,是Derive::f()被调用了。这就实现了多态。

多重继承(无虚函数覆盖)

这里写图片描述

这里写图片描述

  • 每个父类都有自己的虚表。
  • 子类的成员函数被放到了第一个父类的表中。(所谓的第一个父类是按照声明顺序来判断的)
  • 这样做就是为了解决不同的父类类型的指针指向同一个子类实例,而能够调用到实际的函数。

多重继承(有虚函数覆盖)

这里写图片描述

这里写图片描述

  • 三个父类虚函数表中的f()的位置被替换成了子类的函数指针。

注意

  • 不可通过父类型的指针访问子类自己的虚函数
  Base1 *b1 = new Derive();
            b1->f1();  //编译出错
  • 任何妄图使用父类指针想调用子类中的未覆盖父类的成员函数的行为都会被编译器视为非法,所以,这样的程序根本无法编译通过。但在运行时,我们可以通过指针的方式访问虚函数表来达到违反C++语义的行为。(关于这方面的尝试,通过阅读后面附录的代码,相信你可以做到这一点)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值