dynamic_cast在做downcast的時候出了問題.


問題:
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 个解决方案

#1


ChdProcWinDlg *pParent = dynamic_cast<ChdProcWinDlg*>(pwnd->GetParent());
有錯嗎?
為什么我都得到null
直接強轉就ok
ChdProcWinDlg *pParent = (ChdProcWinDlg*)pwnd->GetParent();
(運行期正確)
--------------------
這個肯定是你的運氣好吧

#2


雞丁別跑~~~聽我慢慢說來~~~嘿嘿~~~(逮到個沒睡的)
===================
我也懷疑是我運氣好~
但是pwnd->GetParent()返回的的確是CWnd*
而ChdProcWinDlg的確是從CDialog繼承也就是他先人是CWnd
那我做down_cast為什么不對呢?

看后面....

如果上面那個是運氣好, 那下面的不是運氣好得離譜?

==
直接強轉就ok
ChdProcWinDlg *pParent = (ChdProcWinDlg*)pwnd->GetParent();
(運行期正確)
==

我是指可以正確的access ChdProcWinDlg的實例

#3


我現在是不知道我錯在哪里?
直接用強轉(reinterpret_cast)也正確~~~~~

#4


MFC里的東西沒看,也不知道
還有
ChdProcWinDlg *pParent = dynamic_cast<ChdProcWinDlg*>(pwnd->GetParent());
這個GetParent()返回一個CWnd指針?
那么這個CWnd指針變量是不是指的一個ChdProcWinDlg對象呢?

#5


如果在ChdProcWinDlg里沒有新的數據成員那么用指針訪問可能不會出錯(只要訪問的是基類的成員)

#6


pwnd->GetParent();返回的CWnd*指向pwnd的父窗口類對象, 也就是ChdProcWinDlg的對象
同一個程序里面
如果不在線程中這樣做, 而改在ChdProcWinDlg的子窗口(不是派生類)的方法中進行, 就正確
ChdProcWinDlg *pParent = DYNAMIC_DOWNCAST(ChdProcWinDlg, GetParent());

現在開始懷疑線程函數了......

看來, 我這個問題應該貼到MFC區去, 麻煩哪個斑竹小轉一下~~~

#7


從雞丁的回答來看, 我的dynamic_cast還是沒用錯~~~~

#8


我沒這個權利了,所以幫不了你了。只有等狗狗了

#9


以前碰到這種問題,沒有解決。
幫up

#10


發出帖子心里面急切的想up

我up!!!!!

#11


奶油狗狗~~~~~~小轉一下~~~~幫我轉到MFC版可以不?

#12


幫你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都是這樣。

#13


我也遇到過這種問題,在VC6做的,我以為是VC6對標准支持不好
沒在GCC下試過

當時的解決辦法就是用C的手段 強制轉換

希望能在這找到答案

#14


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?星星們快進來啊,稀奇古怪啊~~~~

#15


分加到100了哦~~~

#16


to qwertasdfg123(無名) 
你得到null是正確的~~~~~因為你的pCA不是指向一個CB的對象

但是我那個就奇怪了, 拋出異常~~~

#17


估計跟編譯器有關,
我在BC5.02中有同樣的問題能編譯過,
在VC6.0里面就不行。

#18


頂喃!頂死你個仙人呢!!!
DYNAMIC_DOWNCAST我都還不會用呢。好像是在api里面用MFC?

#19


找到了~~~~~~

打開編譯器的/GR開關~~~支持RTTI

d:\Workplace\TestSln\test1\test1.cpp(224) : warning C4541: “dynamic_cast”用在了帶 /GR- 的多態類型“B”上;可能導致不可預知的行為

這里都說清楚了~~~怪我笨.....我笨啊那個我笨~~~

怪我笨啊~~~~

#20


結果在線程的函數中
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不可, 哇^_^

#21


哎呀,以前有人也跟我說過是沒有打開RTTI,忘了。

#22


我頂~~~頂啊

#23


#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

#24


core dump !

#25


download cast只是針對有繼承關系的類!可以說你轉換涉及到的兩個類是沒有什么關系的類,所以出錯。

#26


shit,我的好一句話說錯了,其實我不知道的,555555

#27


會是什么問題哪?樓主的情況是下面這樣嗎?
#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;
}

#28


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會返回一個不安全的對象指針。

#29


我的問題代碼:
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~

#30


如果用reinterpret_cast
那么
下面正常訪問到ChdProcWinDlg

#31


to toxyboy(胡言亂語)
你的class里面並沒有virtual函數

#32


使用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
 

#33


據上,
ChdProcWinDlg *pParent = dynamic_cast<ChdProcWinDlg*>(pwnd->GetParent());
用法錯誤,不需要dynamic_cast
直接使用static_cast就可以了。

#34


樓主,給分吧~

#35


幫你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?星星們快進來啊,稀奇古怪啊~~~~

#36


剛剛表述混亂,重發如下:
幫你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

#37


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.
}

#38


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節

#39


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

#40


//////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指針

這樣有什么區別嗎?
如果有的話, 區別在哪里, 錯誤在哪里?



#41


to changeme(笑熬漿糊)
static_cast當然可以~~
我現在問的是我的dynamic_cast在上面兩個地方中為什么一個可以,一個不可以~~
而且據你所說, 必須確定pBase指向的必須是子類對象才可以downcast. 這點, 我已經注意到了, 看上貼, 在類成員函數中用dynamic_cast對GetParent()轉換沒問題, 卻在外面用這個轉換的時候出了問題, why?

#42


加到150分了
參與討論的都分分

#43


GetParent到底返回的是什么類型?
cwnd pwnd和ChdProcWinDlg之間的類關系是怎么樣的?

#44


CWnd* CWnd::GetParent();
CDlgPC* pwnd;
CDlgPC是從CWnd繼承下來的一個類
ChdProcWinDlg是從CWnd繼承下來的一個類
pwnd->GetParent()指向ChdProcWinDlg的實例

#45


用MFC提供的宏DYNAMIC_DOWNCAST情況也一樣

#46


其實,我好想有人給我說MFC的實現是用特別的方法,且不支持RTTI
記得jjhou的<MFC深入潛出>里面說過, 當時MFC並不支持C++標准的RTTI, 是用RUNTIME CLASS的識別鏈表來實現RTTI
結果, 我使用其提供的DYNAMIC_DOWNCAST, 還是不行(在線程里面)
但是疑問的地方, 要是不行,那么請都給我不行, 結果, 卻在類成員函數里面兩個(dynamic_cast, DYNAMIC_DOWNCAST)都通過了.

#47


GetParent方法是返回一個ChdProcWinDlg類型的指針,還是返回一個CWnd類型的指針,但是指向ChdProcWinDlg對象?
第一種情況,絕對OK,除非編譯器對ISO的支持不好。
第二種情況,不可以,dynamic_cast只能用於多態。

我猜你所說的是第二種情況。

#48


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)
         /////////////////////////////////////////////
         
         //....
}

#49


〉MFC里面可以,我卻不行:
首先,前提是你要打開RTTI。
其次,type_info並沒有作為dll的導出部分,所以,MFC內部可以使用type_info,但是使用MFC的代碼卻不知道其type_info

#50


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);



注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com