C++怪谈——C++多态“失灵”

本文通过一个C++示例程序展示了如何正确理解和使用虚函数与对象作用域,特别是针对栈上对象的生命周期管理,避免因作用域理解不当导致的错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

运行环境:vs2012+win7 64 bit

#include <iostream>
using namespace std;
struct VBase
{
    virtual void fun() { cout<<"VBase::fun()" <<endl; };
    ~VBase(){};
    int a ;
};

struct VDerived :public VBase
{
    void fun () { cout<< "VDerived::fun()" <<endl; }
    VDerived(){};
    int b ;
};

int main (int argc, char** argv) {
    VDerived* point = &VDerived ();
    point->fun ();

    VDerived* point2 = new VDerived();
    point2->fun ();
    delete point2 ;

    system("PAUSE" );
    return 0 ;
}

运行结果:

    按照我原本的想法,point和point2都是指向了VDerived 的实例,运行的虚函数fun()应该是VDerived重写的版本,这就是面向对象编程中的三大特性之一——多态。point2按照预期运行了VDerived的版本,但是point却运行了基类版本。这是为什么呢?
    我们先分析一下point指向的是一个局部对象,存储于栈空间,point指向的是一个动态分配的对象,存储于堆空间。
    似乎point的作用域是整个main函数,point->fun()似乎还在作用域之内。

    其实不然,在~VBase(){}处设置一个断点,就会发现当VDerived* point = &VDerived ();执行完成以后,析构函数就被调用了。
然后在调用point->fun ();其实是调用一个已经被析构释放的对象,其结果当然是未知的。
所以,VDerived* point = &VDerived ();中创建的VDerived 对象其实作用域只是这一条语句,这条语句执行完了以后,超出作用域,就直接调用析构函数释放了。

    知道了原因,我们把point相关语句改一下,就恢复正常了。
VDerived v;
VDerived* point = &v;
point->fun();

    但是为什么VDerived* point = &VDerived ();中创建的VDerived 对象作用域只是在一句语句里?C++中除了局部作用域(函数范围),还有语句作用域,一般语句作用域的明显特征就是花括号括起来的语句块,但是在这里并没有看见花括号。查询了C++相关资料,没有得到比较确切的答案,不知道标准中有没有定义。

    所以在使用栈对象时,千万要注意,不要使用这样的语句VDerived* point = &VDerived ();

    同理,下面的语句也是有问题,道理一样,都是语句作用域在做怪,问题比上述的更明显一点。

    VDerived* point;
    if(true){
        VDerived v;
        point = &v;
    }
    point->fun();




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值