迅雷一路C++面试题!求解释
迅雷一道C++面试题!!!求解释
#include <iostream>
using namespace std;
class Base
{
public:
void fun()
{
cout << "Base::fun()" << endl;
}
};
class Derived : public Base
{
public:
virtual void fun()
{
cout << "Derived::fun()" << endl;
}
};
int main()
{
Base *p=new Derived;
p->fun();
delete p;
p=NULL;
return 0;
}
请问各位C++大侠,为什么执行到delete p的时候,运行时崩溃了!!能从对象内存布局角度来解释吗?(个人只知道在执行父类析构函数的时候发生崩溃)
------解决方案--------------------
你不要相减,直接cout出来,
------解决方案--------------------
这文章特意考虑过各种情况,而且说了前提条件。真正的问题是即使是前置基类型的编译器,不见得就会把基类从派生类的基地址开始放,也许会留下一段空缺,后置基类型的编译器也是(那文章写的时候记得还特意注意过措辞,用了“在最好的单继承环境下,可以做到”,“最好的”指的是什么,会不明白吗?还是有意装糊涂?)。而lz给的例子的就在于,基类不含任何的虚函数而派生类有虚函数。但是就是因为基类不含虚析构函数,所以出现通过基类指针无法获得最末端派生类基地址的问题。
#include <iostream>
using namespace std;
class Base
{
public:
void fun()
{
cout << "Base::fun()" << endl;
}
};
class Derived : public Base
{
public:
virtual void fun()
{
cout << "Derived::fun()" << endl;
}
};
int main()
{
Base *p=new Derived;
p->fun();
delete p;
p=NULL;
return 0;
}
请问各位C++大侠,为什么执行到delete p的时候,运行时崩溃了!!能从对象内存布局角度来解释吗?(个人只知道在执行父类析构函数的时候发生崩溃)
------解决方案--------------------
你不要相减,直接cout出来,
------解决方案--------------------
嗯,3q,有点明白了。但是我搞不懂的一点是,即使是内存泄露,怎么会造成运行时崩溃呢?
派生类有虚函数,使用了动态联编,会在类里面多出一个vptr指针来指向虚函数表,以及多出来的一张虚函数表。delete p只是调用基类的析构函数,很明显没有释放派生类里面多出来的内容,造成内存泄露。 这边你可以声明一个虚拟的析构函数,也可以将基类中的fun函数也声明为虚拟的,这样的话,基类中就会也有vptr,和虚函数表,派生类只是继承这些内容。因此在基类的析构就足以将需要释放的资源释放了
这边会崩溃是因为以基类指针来存储来存储派生类的地址和用存储派生类地址,值是不一样的,你上面这篇文章说的是错的http://blog.****.net/unituniverse2/article/details/12302139,不信你可以打印出来看看,
Derived *sp=new Derived;
Base *p=sp;
这边差4,恰好是一个指针的大小。
崩溃的原因是因为detlete p;将调用 全局的void operator delete( void * addr, size_t size),这边穿进去的是基类部分的指针,在函数里面要free(addr),但是我们new 的时候调用的malloc()并不是new出的addr这块内存,而是sp指向派生类的地址,free和malloc不匹配当然会崩溃。http://www.wuzesheng.com/?p=840这边看看就懂了
这文章特意考虑过各种情况,而且说了前提条件。真正的问题是即使是前置基类型的编译器,不见得就会把基类从派生类的基地址开始放,也许会留下一段空缺,后置基类型的编译器也是(那文章写的时候记得还特意注意过措辞,用了“在最好的单继承环境下,可以做到”,“最好的”指的是什么,会不明白吗?还是有意装糊涂?)。而lz给的例子的就在于,基类不含任何的虚函数而派生类有虚函数。但是就是因为基类不含虚析构函数,所以出现通过基类指针无法获得最末端派生类基地址的问题。