虚函数的一点总结

    最近看编程规范时看到关于虚函数的一些说明,参考了《深入浅出MFC》书中的说明,对虚函数有了一点想法,总结下来以便以后回顾。

虚函数为什么可以实现动态绑定实现多态?
首先需要明确类对象在内存中的分配,有两个方面需要说明。首先是类成员变量,每个类对象的成员变量在程序中都拥有自己的专有内存,保存着自己的内容。其次类成员函数对所有对象来说都是共用的,类成员函数在内存中只有一份代码。
对于非虚函数来说,编译器会根据对象的类型定位到指定的函数地址,因此无论基类的指针指向的是哪个对象,其都会调用基类的函数,这是在编译时就确定好的。
对于虚函数来说情况就不一样了,为了实现运行时多态,当我们在类中定义虚函数时,编译器会在类中添加一个指向虚函数表的指针,该指针位于类对象的起始位置。虚函数表可以看作是一个函数指针数组,里面包含的是类定义的虚函数地址。
示例如下:
class base
{
public:
    virtual void show(void)
    {
        cout << "this is base::show" << endl;
    }
public:
    int a;
};
void main(void)
{
    base b;
    cout << sizeof(b) <<endl;
    cout << &b << "\r\n" << &b.a << endl;
}

输出结果为:
我们使用基类指针指向派生类对象,在调用虚函数时,程序就会从对象内存中找到指向虚函数表的指针,虽然我们使用的是基类的指针,但指向的内存是派生类对象的专有内存,因此找到的指针指向的也是派生类的虚函数表,从而在虚函数表中找到也是派生类虚函数的地址,从而实现了运行时多态。

在举个例子:
class base
{
public: 
   virtual void show(void)
    {
        cout << "this is base::show" << endl; 
    }
};
class derived : public base
{
public:
    virtual void show(void)
    {
        cout << "this is derived::show" <<endl;
    }
};
void main(void)
{
    derived d;
    base *pBase = &d;
    pBase->show();
    ((base *)(&d))->show();
    ((base)d).show();
}

输出代码的输出为


前两行输出与我们预期的一样,无论怎么变化,始终调用的是d专有内存中的内容,但第三行却出乎意料,难道调用的已经不是d的专有内存了?我们可以试验一下,在main函数里加入如下代码,
cout << &d << endl;
cout << &((base)d) << endl;
输出为

果然强制转换之后 (base)d已经不是原来的内存了,当我们执行(base)d语句时,编译器已经为我们创建了一个临时变量,该变量的类型就是base(毕竟我们要的就是base类型的变量),那么在新的内存中保存的自然也就是指向base虚函数表的指针了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值