运行环境: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();