|
|
|
|
 关于虚基类的强制转换所引发的crash. - ganxj [ 2006-02-21 19:02 | 891 byte(s)]
 Re: 关于虚基类的强制转换所引发的crash. - ganxj [ 2006-03-05 17:14 | 1,239 byte(s)]
 Re: 关于虚基类的强制转换所引发的crash. - ddd [ 2006-03-05 19:36 | 243 byte(s)]
 Re: 关于虚基类的强制转换所引发的crash. - ganxj [ 2006-03-07 21:30 | 8 byte(s)]
 Re: 关于虚基类的强制转换所引发的crash. - acguy [ 2006-02-23 12:36 | 839 byte(s)]
 Re: 关于虚基类的强制转换所引发的crash. - ddd [ 2006-02-22 20:11 | 57 byte(s)]
 Re: 关于虚基类的强制转换所引发的crash. - cjhsh [ 2006-02-21 19:48 | 3 byte(s)]
 Re: 关于虚基类的强制转换所引发的crash. - ganxj [ 2006-02-21 21:05 | 35 byte(s)]
 Re: 关于虚基类的强制转换所引发的crash. - drangon_zhou [ 2006-02-21 21:12 | 129 byte(s)]
 Re: 关于虚基类的强制转换所引发的crash. - ganxj [ 2006-02-22 12:39 | 629 byte(s)]
 Re: 关于虚基类的强制转换所引发的crash. - cjhsh [ 2006-02-22 13:54 | 387 byte(s)]
 Re: 关于虚基类的强制转换所引发的crash. - ganxj [ 2006-02-22 15:10 | 20 byte(s)]
|
|
|
|
[Original]
[Print]
[Top]
|
Hi, 我碰到一个crash如下:
class A{
...
}
class B{ //vitual class
...
virtual fun1() = 0;
}
class C1 : public A,public B{
...
fun1(){...};
}
class C2 : public A,public B{
fun1(){...};
}
I pass the C1 object point "mypointer" to a function as void* then call fun1() it crash
extern "C"{
...
function(void * mypointer)
{
((B*)mypointer)->fun1();
}
}
but if I change
((B*)mypointer)->fun1();
to
((C1*)mypointer)->fun1();
it would be OK
Thanks for suggestion to avoid the crash
gan
|
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
不能强制类型转换吧,考虑使用dynamic_cast,如果要支持RTTI,
指向同一个对象的不同类型的pointer的位置的不一样的。
|
|
----
岂有豪情似旧时,花开花落两由之。
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
我试了一下
class A{
...
}
class B{ //vitual class
...
virtual fun1() {};
}
class C1 : public A,public B{
...
fun1(){...};
}
class C2 : public A,public B{
fun1(){...};
}
C1* g = new C1();
void * x = g;
B* j= dynamic_cast <B*>((B*)x);
j->fun1();
仍然crash,是否在void * x = g;信息就丢了?dynamic_cast也找不到最派生类的指针了。
|
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
今天翻了翻书看虚函数的用法
发现偶昨天的回答是错地
如果想通过派生类调用基类的函数要加上作用域
如
C1* g = new C1();
void * x = g;
B* j= dynamic_cast <B*>((B*)x);
j->fun1();
改成
j->B::fun1();就可调用基类的fun1
|
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
#include <iostream>
using namespace std;
做了个测试:
class A {
};
class B {
public:
virtual void fun();
};
class C : public A, public B {
public:
void fun();
};
void B::fun(){
cout<<"B function"<<endl;
}
void C::fun(){
cout<<"C function"<<endl;
}
int main(int argv, char *args[])
{
C *cp = new C();
void * vp = cp;
((B*)vp)->fun();
return 0;
}
结果输出 “C function",完全正常。
|
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
网上问了一圈,觉得有一个解释有道理,贴在这里,如果谁碰到同样现象事供参考:
The problem is in wrong pointer conversion: C1* -> void* -> B*.
Conversion to/from void* assumes that both pointers refer to same
address.
But B is a second base of C1, and its subobject is shifted.
Thus, doing C1* -> void* -> B* you get an invalid pointer (of type B*
that refers to A subobject, not to B).
Dereferencing it leads to UB.
The program tries to read vfptr and get some junk value. And then
fails:
- dereferencing wrong vfptr and trying to read vtbl
- reading wrong address of fun1 and trying to jump there
- executing wrong instructions
and so on, and so on...
What to do:
As far as you know that your function(void*) accepts B*, you have to
pass B* there:
function( static_cast<B*>(ptrC1) );
Using static_cast<B*>(ptrC1) instead of C-style (B*)ptrC1 will protect
you from mistakes. If ptrC1 is not of type derived from B, the compiler
indicate an error.
|
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
这个外国人说对一半。
A中如果没有虚函数,那么不会发生shift事件。
所以这个情况出现的必要条件是A有虚函数。
static_cast<B*>(ptr)如果这个ptr类型是void*,并且是从C*转换过来的,那么这个表达式的结果和(B*)一样。
|
|
----
I solemnly swear that I am up to no good
|
|
[Original]
[Print]
[Top]
|
|
|