問題:
ChdProcWinDlg *pParent = dynamic_cast<ChdProcWinDlg*>(pwnd->GetParent());
有錯嗎?
為什么我都得到null
直接強轉就ok
ChdProcWinDlg *pParent = (ChdProcWinDlg*)pwnd->GetParent();
(運行期正確)
環境:
這個是在線程里面, 需要使用到窗口類中的方法
pwnd 是通過 DWORD WINAPI ThreadFunc(LPVOID)中傳過去的參數用reinterpret_cast轉換得到:
CDlgPC * pwnd = reinterpret_cast<CDlgPC*>(lpParam);
CDlgPC是ChdProcWinDlg的子窗口
牢騷:
CWnd => ChdProcWinDlg 是一個 downcast啊~
難道是我對dynamic_cast理解有偏差?
還是GetParent();給我的不是CWnd*
昏了~~
附加:
同樣的問題, 出在下面:
(1)
CWnd *pwnd = CWnd::FromHandle(GlobalVar.hwnd_main);
Dlg_Main *pdlg = DYNAMIC_DOWNCAST(Dlg_Main, pwnd);
運行期正確
(環境: 用在dll的函數里面, 需要修改到hwnd_main這個窗口內的一些數據)
(2)
Dlg_Main *pdlg = DYNAMIC_DOWNCAST(Dlg_Main, GetParent());
運行期正確
(環境: 用在Dlg_Main子窗口內)
(3)
ChdProcWinDlg *pParent = DYNAMIC_DOWNCAST(ChdProcWinDlg, pwnd->GetParent());
運行期錯誤(NULL)
(環境同最上面的一樣)
開發工具: VC.NET 2003
ps:不知道該po在哪邊, 屬於MFC還是C++的問題?
57 个解决方案
ChdProcWinDlg *pParent = dynamic_cast<ChdProcWinDlg*>(pwnd->GetParent());
有錯嗎?
為什么我都得到null
直接強轉就ok
ChdProcWinDlg *pParent = (ChdProcWinDlg*)pwnd->GetParent();
(運行期正確)
--------------------
這個肯定是你的運氣好吧
雞丁別跑~~~聽我慢慢說來~~~嘿嘿~~~(逮到個沒睡的)
===================
我也懷疑是我運氣好~
但是pwnd->GetParent()返回的的確是CWnd*
而ChdProcWinDlg的確是從CDialog繼承也就是他先人是CWnd
那我做down_cast為什么不對呢?
看后面....
如果上面那個是運氣好, 那下面的不是運氣好得離譜?
==
直接強轉就ok
ChdProcWinDlg *pParent = (ChdProcWinDlg*)pwnd->GetParent();
(運行期正確)
==
我是指可以正確的access ChdProcWinDlg的實例
我現在是不知道我錯在哪里?
直接用強轉(reinterpret_cast)也正確~~~~~
MFC里的東西沒看,也不知道
還有
ChdProcWinDlg *pParent = dynamic_cast<ChdProcWinDlg*>(pwnd->GetParent());
這個GetParent()返回一個CWnd指針?
那么這個CWnd指針變量是不是指的一個ChdProcWinDlg對象呢?
如果在ChdProcWinDlg里沒有新的數據成員那么用指針訪問可能不會出錯(只要訪問的是基類的成員)
pwnd->GetParent();返回的CWnd*指向pwnd的父窗口類對象, 也就是ChdProcWinDlg的對象
同一個程序里面
如果不在線程中這樣做, 而改在ChdProcWinDlg的子窗口(不是派生類)的方法中進行, 就正確
ChdProcWinDlg *pParent = DYNAMIC_DOWNCAST(ChdProcWinDlg, GetParent());
現在開始懷疑線程函數了......
看來, 我這個問題應該貼到MFC區去, 麻煩哪個斑竹小轉一下~~~
從雞丁的回答來看, 我的dynamic_cast還是沒用錯~~~~
奶油狗狗~~~~~~小轉一下~~~~幫我轉到MFC版可以不?
幫你up。
如下我試了也不行。
class CA
{
public:
virtual void foo(){}
}
class CB: public CA
{
virtual void foo1(){}
};
int main()
{
CA *pCA = new CA;
CB *pCB = new CB;
pCB = dynamic_cast<CB*>(pCA); // 得出的pCB=0x00000000.
}
編譯環境是gcc、vc6都是這樣。
我也遇到過這種問題,在VC6做的,我以為是VC6對標准支持不好
沒在GCC下試過
當時的解決辦法就是用C的手段 強制轉換
希望能在這找到答案
class B {
public:
virtual void s(){}
};
class D : public B {
public:
virtual void s(){}
};
B* pb = new D;
D* pd = dynamic_cast<D*>(pb); //拋出異常, why?
編譯時候出現警告:
d:\Workplace\TestSln\test1\test1.cpp(224) : warning C4541: “dynamic_cast”用在了帶 /GR- 的多態類型“B”上;可能導致不可預知的行為
環境: VC.NET 2003
上面的程序來自MSDN
ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.2052/vclang/html/_pluslang_dynamic_cast_Operator.htm
example:
class B { ... };
class D : public B { ... };
void f()
{
B* pb = new D; // unclear but ok
B* pb2 = new B;
D* pd = dynamic_cast<D*>(pb); // ok: pb actually points to a D
...
D* pd2 = dynamic_cast<D*>(pb2); // pb2 points to a B not a D
// cast was bad so pd2 == NULL
...
}
why?星星們快進來啊,稀奇古怪啊~~~~
to qwertasdfg123(無名)
你得到null是正確的~~~~~因為你的pCA不是指向一個CB的對象
但是我那個就奇怪了, 拋出異常~~~
估計跟編譯器有關,
我在BC5.02中有同樣的問題能編譯過,
在VC6.0里面就不行。
頂喃!頂死你個仙人呢!!!
DYNAMIC_DOWNCAST我都還不會用呢。好像是在api里面用MFC?
找到了~~~~~~
打開編譯器的/GR開關~~~支持RTTI
d:\Workplace\TestSln\test1\test1.cpp(224) : warning C4541: “dynamic_cast”用在了帶 /GR- 的多態類型“B”上;可能導致不可預知的行為
這里都說清楚了~~~怪我笨.....我笨啊那個我笨~~~
怪我笨啊~~~~
結果在線程的函數中
ChdProcWinDlg *pParent = dynamic_cast<ChdProcWinDlg*>(pwnd->GetParent());
這個pParent還是等於NULL
非要我用reinterpret_cast不可
我確信pwnd->GetParent()得到的指針是指向一個ChdProcWinDlg的對象的, 但是兩者之間pwnd和ChdProcWinDlg並無繼承關系(子窗口和父窗口關系), 只是都是從CWnd派生出來的.
所以我覺得從CWnd* downcast成一個派生類的對象指針並無問題.
在MFC的消息處理中
ChdProcWinDlg *pParent = dynamic_cast<ChdProcWinDlg*>(GetParent());
卻是正確的
現在確定了, 應該是MFC的使用問題~
我繼續研究, 哪位高手來點撥一下~~
ps:這貼我非加FAQ不可, 哇^_^
哎呀,以前有人也跟我說過是沒有打開RTTI,忘了。
#include <iostream>
using namespace std;
class A
{
public:
virtual void test(){ cout << "this is Father!" << endl; };
};
class B : public A
{
public :
void test(){
cout << "this is son!" << endl;
};
};
int main(int argc,char** argv)
{
A *pA = new A();
B *pB = new B();
pB = dynamic_cast<B*>(pA);
pB->test();
if(pA)
delete pA;
pA = NULL;
if(pB)
delete pB;
pB = NULL;
return 0;
}
"test.cpp" 33L, 408C written
[root@doors virtest]# g++ -g -o test test.cpp
[root@doors virtest]# ./test
Segmentation fault
#gdb test
(gdb) run
Starting program: /home/toxyboy/myproc/virtest/test
Program received signal SIGSEGV, Segmentation fault.
0x08048848 in main (argc=1, argv=0xbffff8c4) at test.cpp:24
24 pB->test();
(gdb) kill
download cast只是針對有繼承關系的類!可以說你轉換涉及到的兩個類是沒有什么關系的類,所以出錯。
shit,我的好一句話說錯了,其實我不知道的,555555
會是什么問題哪?樓主的情況是下面這樣嗎?
#include "stdafx.h"
#include <windows.h>
#include <process.h>
#include <iostream>
using namespace std;
struct A
{
virtual void test()
{ cout<<"A created"<<endl; }
};
struct B : A
{
void test()
{ cout<<"B created"<<endl; }
};
B b;
A* a;
unsigned WINAPI thread_func(void *)
{
B *b = 0;
b = dynamic_cast<B*>(a);
b->test();
return 0;
}
int main(int argc, char* argv[])
{
unsigned dwTh;
a = &b;
::_beginthreadex(NULL, 0, thread_func, 0, 0, &dwTh);
Sleep(2000);
return 0;
}
dynamic_cast是一種UpCast轉換,也就是可以從派生類用
base *p = dynamic_cast<base*>(pDerived)來得到其基類的指針,
這種情況下要注意的是Multiple Inheritance,而相反DownCast就不可以。
如果需要,可以采用static_cast。
在Upcast方面, static_cast與dynamic_cast有相同的表現,而在DownCast方面,dynamic_cast會返回NULL,dynamic_cast會返回一個不安全的對象指針。
我的問題代碼:
DWORD WINAPI ThreadFunc(LPVOID lpParam)
{
CDlgPC *pwnd = reinterpret_cast<CDlgPC*>(lpParam);
assert(pwnd);
ChdProcWinDlg *pParent = reinterpret_cast<ChdProcWinDlg*>(pwnd->GetParent());
assert(pParent); //上面一行如果用dynamic_cast那么assert fault
//...
}
pwnd->GetParent()返回的是CWnd*, 這個CWnd*應該指向ChdProcWinDlg*
在MFC的消息映射函數中用downcast沒錯~
而在線程里面用downcast就錯了~
還在苦惱ing~
如果用reinterpret_cast
那么
下面正常訪問到ChdProcWinDlg
to toxyboy(胡言亂語)
你的class里面並沒有virtual函數
使用dynamic_cast作為upcast時,一般不會有問題,但是在做downcast時,一定要主意:
假設有兩個類 A和B,其中B繼承了A, a和b分別是A, B的實例指針
a = dynamic_cast<A*>(b); //沒問題
b = dynamic_cast<B*>(a); //小心
你必須知道a雖然是A*類型的,但是實際上在程序中,他指向了一個B*的對象。
否則,dynamic_cast返回值為0。
也就是說,一般情況下,不推薦使用dynamic_cast,除非為了強制實現多態(原來類中方法未申明為virtual)
如下:
class A
{
public:
void f(){...}
};
class B
{
public:
void f(){...}
};
void func1(A* a)
{
//RTTI
B* b;
if( b=dynamic_cast<A*>(a) ) //判斷a是指向A*對象的還是B*對象,如果不是指向B*,則返回0
{
b->f();
}
else
{
a->f();
}
}
以上可以通過虛函數的多態來實現,但是如果類設計時不合理,也可以通過dyanmic_cast來間接使用RTTI
據上,
ChdProcWinDlg *pParent = dynamic_cast<ChdProcWinDlg*>(pwnd->GetParent());
用法錯誤,不需要dynamic_cast
直接使用static_cast就可以了。
幫你up。
如下我試了也不行。
class CA
{
public:
virtual void foo(){}
}
class CB: public CA
{
virtual void foo1(){}
};
int main()
{
CA *pCA = new CA;
CB *pCB = new CB;
pCB = dynamic_cast<CB*>(pCA); // 得出的pCB=0x00000000.
}
編譯環境是gcc、vc6都是這樣。
====================
int main()
{
CA *pCA = new CA; /////注意這里nwe CA,決定了pCB = dynamic_cast<CB*>(pCA); // 得出的pCB=0x00000000
CB *pCB = new CB;
pCB = dynamic_cast<CB*>(pCA); // 得出的pCB=0x00000000.
}
MS的那個例子也是一樣道理
上面的程序來自MSDN
ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.2052/vclang/html/_pluslang_dynamic_cast_Operator.htm
example:
class B { ... };
class D : public B { ... };
void f()
{
B* pb = new D; // unclear but ok
B* pb2 = new B;
D* pd = dynamic_cast<D*>(pb); // ok: pb actually points to a D
...
D* pd2 = dynamic_cast<D*>(pb2); // pb2 points to a B not a D
// cast was bad so pd2 == NULL
...
}
why?星星們快進來啊,稀奇古怪啊~~~~
剛剛表述混亂,重發如下:
幫你up。
如下我試了也不行。
class CA
{
public:
virtual void foo(){}
}
class CB: public CA
{
virtual void foo1(){}
};
int main()
{
CA *pCA = new CA;
CB *pCB = new CB;
pCB = dynamic_cast<CB*>(pCA); // 得出的pCB=0x00000000.
}
===================================================================================================================================================================================================================================================
int main()
{
CA *pCA = new CA; /////注意這里nwe CA,決定了pCB = dynamic_cast<CB*>(pCA); // 得出的pCB=0x00000000
CB *pCB = new CB;
pCB = dynamic_cast<CB*>(pCA); // 得出的pCB=0x00000000.
}
MS的那個例子也是一樣道理
上面的程序來自MSDN
int main()
{
CA *pCA = new CA; ///如果這里是CA *pCA = new CB,則pCB = dynamic_cast<CB*>(pCA); 也應該不回是0x00000000
CB *pCB = new CB;
pCB = dynamic_cast<CB*>(pCA); // 得出的pCB=0x00000000.
}
TO wshcdr(DD)
dynamic_cast不是這樣用的
如果pCA不是指向CB的指針,使用dynamic_cast返回當然是0了。
我上面說的很清楚了,如果使用down cast,需要小心
dynamic_cast主要的用處其實是用來確認多態對象的類型,用在RTTI中。
用法和一般的cast不同。
如果只是需要在基類與派生類之間簡單的進行類型轉換,用static_cast.
見The C++ Standard Library 2.2.7節
dynamic_cast<A type>(B type)
如果時downcast的哈,dynamic_cast會檢查是否B type真的指向A type的對象,如果不是,會返回0
例如
class A{};
class B:public A{};
....
B b;
A *pa =&b;
B *pb = dynamic_cast<B*><pa>; //SUCCESS
....
A a;
A *pa = &a;
B *pb = dynamic_cast<B*><pa>; //get NULL point
//////quote////////
b = dynamic_cast<B*>(a); //小心
你必須知道a雖然是A*類型的,但是實際上在程序中,他指向了一個B*的對象。
否則,dynamic_cast返回值為0。
///////////////////
我確定pwnd->GetParent()得到的這個CWnd*指向ChdProcWinDlg
//////quote////////
B b;
A *pa =&b;
B *pb = dynamic_cast<B*><pa>; //SUCCESS
///////////////////
當然success, 見前面的程序
我說過在CDlgPC::func()中
dynamic_cast<ChdProcWinDlg*>(GetParent());
正確
不過在一個線程函數里面DWORD WINAPI ThreadFunc(LPVOID lpParam)里面
CDlgPC* pwnd = reinterpret_cast<CDlgPC*>(lpParam);
dynamic_cast<ChdProcWinDlg*>(pwnd->GetParent()); //這里不行, 為NULL
lpParam是在CDlgPC里面傳過去的this指針
這樣有什么區別嗎?
如果有的話, 區別在哪里, 錯誤在哪里?
to changeme(笑熬漿糊)
static_cast當然可以~~
我現在問的是我的dynamic_cast在上面兩個地方中為什么一個可以,一個不可以~~
而且據你所說, 必須確定pBase指向的必須是子類對象才可以downcast. 這點, 我已經注意到了, 看上貼, 在類成員函數中用dynamic_cast對GetParent()轉換沒問題, 卻在外面用這個轉換的時候出了問題, why?
GetParent到底返回的是什么類型?
cwnd pwnd和ChdProcWinDlg之間的類關系是怎么樣的?
CWnd* CWnd::GetParent();
CDlgPC* pwnd;
CDlgPC是從CWnd繼承下來的一個類
ChdProcWinDlg是從CWnd繼承下來的一個類
pwnd->GetParent()指向ChdProcWinDlg的實例
用MFC提供的宏DYNAMIC_DOWNCAST情況也一樣
其實,我好想有人給我說MFC的實現是用特別的方法,且不支持RTTI
記得jjhou的<MFC深入潛出>里面說過, 當時MFC並不支持C++標准的RTTI, 是用RUNTIME CLASS的識別鏈表來實現RTTI
結果, 我使用其提供的DYNAMIC_DOWNCAST, 還是不行(在線程里面)
但是疑問的地方, 要是不行,那么請都給我不行, 結果, 卻在類成員函數里面兩個(dynamic_cast, DYNAMIC_DOWNCAST)都通過了.
GetParent方法是返回一個ChdProcWinDlg類型的指針,還是返回一個CWnd類型的指針,但是指向ChdProcWinDlg對象?
第一種情況,絕對OK,除非編譯器對ISO的支持不好。
第二種情況,不可以,dynamic_cast只能用於多態。
我猜你所說的是第二種情況。
void CDlgPC::start(void)
{
products_ = 0;
mx_ = 1;
full_mx_ = 0;
empty_mx_ = m_maxproducts;
GetDlgItem(IDC_EDIT_MAXPRODUCT)->EnableWindow(FALSE);
mx = new CSemaphore(1, 1);
full_mx = new CSemaphore(0, m_maxproducts);
empty_mx = new CSemaphore(m_maxproducts, m_maxproducts);
/////////////////////////////////////////////
ChdProcWinDlg *pParent = dynamic_cast<ChdProcWinDlg*>(GetParent());
assert(pParent); // success
/////////////////////////////////////////////
pParent->logtomsg("** PRODUCER-CONSUMER Problem TEST **");
m_hProducer = CreateThread(NULL, 0, producer, this, 0, NULL);
// here pass "this" to producer(LPVOID)
m_hConsumer = CreateThread(NULL, 0, consumer, this, 0, NULL);
}
DWORD WINAPI producer(LPVOID lpParam)
{
char buf[256];
CDlgPC *pwnd = reinterpret_cast<CDlgPC*>(lpParam);
assert(pwnd);
/////////////////////////////////////////////
ChdProcWinDlg *pParent = dynamic_cast<ChdProcWinDlg*>(pwnd->GetParent());
assert(pParent); // 0x00000000 why? here both static_cast and reinterpret_cast got no problem (of cause)
/////////////////////////////////////////////
//....
}
〉MFC里面可以,我卻不行:
首先,前提是你要打開RTTI。
其次,type_info並沒有作為dll的導出部分,所以,MFC內部可以使用type_info,但是使用MFC的代碼卻不知道其type_info
class CA
{
public:
virtual void foo(){}
};
class CB: public CA
{
virtual void foo1(){}
};
int main()
{
CB *pCB = new CB;
pCA = dynamic_cast<CA*>(pCB); // 正確用法.
CA *pCA = new CA;
CB *pCB1 = dynamic_cast<CB*>(pCA); // 錯誤用法.
return ;
}
正確:
ChdProcWinDlg *pParent = static_cast<ChdProcWinDlg*>(pwnd->GetParent());
試試看:
ChdProcWinDlg *pParent = dynamic_cast<ChdProcWinDlg*>(pwnd);