悬浮指针,虚函数,逗号运算符等知识点综合题
class A
{
public:
~A(){cout<<"A is dead"<<endl;}
void virtual f()
{
cout<<"A"<<endl;
}
};
class B
{
public:
~B(){cout<<"B is Dead"<<endl;}
void virtual f()
{
cout<<"B"<<endl;
}
};
int main()
{
A*pa=new A();//@1
pa->f();//@2
B* pb=(B*)pa;//@3
pb->f();//@4
delete pa,pb;//@5
B *pc=new B();//@6
pc->f();//@7
pa->f();//@8
return 0;
}
这道题纯粹是应试教育背景下诞生的题目,现实中谁写出这样的东东。。。哎。。批评结束,俺要问大家几个问题哈。。。
1.@5处只执行了delete pa(是不是因为逗号表达式的缘故?)
2.@8处输出B,说明pa指向的内存虽然被释放但内容没改变。(总觉得怪怪的,那块内存到底释放了没?)
3.关于虚指针,主要是@3处,强制转换后虚指针有甚么变化?
运行到@5时,单步调试(自己回去试下)
pb--------0x004319a0
|-[A]------{....}
|-__vfptr-----0x42601c
那个[A]是甚么东西??
还请高手们详解啊》》》》
[解决办法]
1.@5处只执行了delete pa(是不是因为逗号表达式的缘故?)
----
是
2.@8处输出B,说明pa指向的内存虽然被释放但内容没改变。(总觉得怪怪的,那块内存到底释放了没?)
-----
释放了
3.关于虚指针,主要是@3处,强制转换后虚指针有甚么变化?
---
虚函数的多态机制是根据VPtr指向VTable来确定的,此时pb指向的缓存里存储的是类A的VPtr,
所以调用的是类A版本的f()
[解决办法]
1.@5处只执行了delete pa(是不是因为逗号表达式的缘故?)
应该是逗号表达式 ,delete pa作为一个表达式,pb作为一个表达式,所以执行了delete pa
2.@8处输出B,说明pa指向的内存虽然被释放但内容没改变。(总觉得怪怪的,那块内存到底释放了没?)
对于一块释放了的内存,使用它是没有意义的,不要管它的值是什么,因为没有意义,所谓释放内存,就是将
内存的使用权归还系统,不代码将内存内容清空
3.关于虚指针,主要是@3处,强制转换后虚指针有甚么变化?
强制转化后,B类的虚表函数指针指向了A类的虚表函数指针,出现这种情况是因为位拷贝造成的(一家之言)
显然,A,B类的结构是一样的,才出现了这种现象,比如在B类的f函数前加个virtual void test(void);
结果很明显
[解决办法]
1.@5处只执行了delete pa(是不是因为逗号表达式的缘故?)
---------
是
因为逗号运算符的优先级比delete低,如果改成
delete (pa,pb);//@5
那么就只释放了 pb
2.@8处输出B,说明pa指向的内存虽然被释放但内容没改变。(总觉得怪怪的,那块内存到底释放了没?)
--------
释放了,但又声情回来了
delete pa,pb;//@5 // 把pa指向的空间释放了
B *pc=new B();//@6 // 给pc声情了空间,由于编译器内存管理的问题(vc),这个pc的空间刚好是前面释放的pa的空间
pc- >f();//@7
pa- >f();//@8 // 所以pa的空间又有效了(和pc指向同一个空间)
你可以把B *pc=new B();去了,运行就回有问题
[解决办法]
1. 没错。
2. delete除了执行析构当作,把pa指向的内存标识为未占用,但是那块内存的内容暂时还没有改变,仍然包含原来的有效的可执行代码,所以@8还可以勉强执行。这种做法是不应该提倡的,如果该内存块由于多线程等原因被覆盖,马上会产生AV。
3. 类型转换时保留基类的virtual table。
悬浮指针,虚函数,逗号运算符等知识点综合题解决思路
悬浮指针,虚函数,逗号运算符等知识点综合题class A{public:~A(){coutA is deadendl}void virtual f
