RTTI为什么不好用?

stellarguy 2008-03-30 11:55:52
vs2003 / vc6 rtti 选项已经开启
在一个对话框类中的一个按钮click事件中:
语句:
CEdit *lpEdit = dynamic_cast<CEdit*>(GetDlgItem( IDC_EDIT1 )); // 控件及id确实存在

执行后 lpEdit 为NULL,

为什么?
...全文
123 点赞 收藏 15
写回复
15 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
Mr-Chen 2008-04-02
看来你只能使用强制类型转换
CEdit *lpEdit = reinterpret_cast <CEdit*>(GetDlgItem( IDC_EDIT1 ));
回复
Mr-Chen 2008-04-01
用法有问题,基类转换成派生类,需要强制转换
dynamic_cast Operator
C++ Specific

dynamic_cast < type-id > ( expression )

The expression dynamic_cast< type-id >( expression ) converts the operand expression to an object of type type-id. The type-id must be a pointer or a reference to a previously defined class type or a "pointer to void". The type of expression must be a pointer if type-id is a pointer, or an l-value if type-id is a reference.

可以使用CEdit *pEdit = (CEdit *)(this->GetDlgItem(IDC_EDIT1));
回复
scq2099yt 2008-04-01
两者没关系
回复
Yofoo 2008-04-01
CEdit *lpEdit = dynamic_cast <CEdit*>(GetDlgItem( IDC_EDIT1 )); // 控件及id确实存在
执行后 lpEdit 为NULL,
为什么?

GetDlgItem缺省是CWnd *类型, 从子类到父类转换肯定不行

CWnd *pWnd = dynamic_cast<CWnd*>(GetDlgItem(IDC_EDIT1));
这样就OK了



MFC的GetDlgItem 最终通过 CWnd::FromHandle来实现

MFC的窗体管理是用一个list 来映射所有的HWND 和CWnd

当调用 FromHandle 时, 如果HWND 不存在就会创建一个CWnd与之对应, 再返回

所以当用了DDX_Control 就会一个CEdit就会与HWND对应, 所以返回的是 CEdit *, 所以OK


回复
stellarguy 2008-04-01
刚才总结了一下,感觉其实这个问题不难,只是一心以为是 rtti 之类的转换用法错误,所以将基本的忽略了。

其实 如果 在MFC 的框架中的对话框类中, DDX_Control(pDX, IDC_EDIT1, m_Edit); 的作用是控件与 相关的控件类绑定。
我个人认为绑定的实质是内部变量实例的创建和句柄的赋值(具体没研究)。

DDX_Control(pDX, IDC_EDIT1, m_Edit); 调用后, CEdit 类与 对话框窗体内子控件IDC_EDIT1 绑定,创建了 IDC_EDIT1 的CEdit 类。

而mfc 机制,如果子控件 被绑定 ,则 GetDlgItem 函数返回的是 创建的 控件类(如 CEdit) 的指针
如果 未绑定 ,则只是返回 窗口对象句柄而已(HWND)。

所以上面 RTTI 不好用,是因为 没有绑定控件,所以只是返回单纯的 控件 句柄 HWND而已,而不是 CEdit 或者 CWnd ,
所以上面的各种转换,当然也就不起作用了。

并不是 rtti 或者 IsKindOf 之类的类型转换函数的用法不对。


结贴了,祝大家愚人节快乐!!!
回复
stellarguy 2008-04-01
刚刚发现。如果给 IDC_EDIT1 控件添加变量,如 m_Edit ,在 DoDataExchange 函数中执行 DDX_Control(pDX, IDC_EDIT1, m_Edit);
语句,上述所有转换均可用。

所以上述各种用法单从 用法上讲,肯定没错。
不过为什么 不执行 DDX_Control(pDX, IDC_EDIT1, m_Edit); 就 不可以转换?

这个正在研究中......
回复
stellarguy 2008-04-01
经试验:上面三段代码,得到的仍然是NULL
// vc6.0 , rtti 已经开启。

甚至于:
BOOL bln = pActiveEdit->IsKindOf(RUNTIME_CLASS(CEdit));

返回的也是FALSE;

不知道为啥。
回复
Mr-Chen 2008-04-01
dynamic_cast是把指向基类的指针或引用转换成指向其派生类或其兄弟类的指针或引用,失败的转换将返回空指针(当对指针进行类型转换时)或者抛出异常(当对引用进行类型转换时)。
经实验,以下使用方法都正确:


CEdit *lpEdit = dynamic_cast <CEdit*>((CWnd *)GetDlgItem( IDC_EDIT1 ));



CEdit *lpEdit = NULL;
CWnd * pActiveEdit = GetDlgItem( IDC_EDIT1 );
if(pActiveEdit)
{
lpEdit = dynamic_cast<CEdit*>(pActiveEdit); // pEdit gets null
}


或者使用DYNAMIC_DOWNCAST

CEdit *lpEdit = NULL;
CWnd * pActiveEdit = GetDlgItem( IDC_EDIT1 );
if(pActiveEdit)
{
lpEdit = DYNAMIC_DOWNCAST(CEdit, pActiveEdit);
}
回复
Mr-Chen 2008-04-01
或者使用reinterpret_cast


CEdit *lpEdit = reinterpret_cast <CEdit*>(GetDlgItem( IDC_EDIT1 ));
回复
hdqqq 2008-03-31
抱歉,上面错误,是从基类到子类,需要虚函数.

但是dynamic_cast在将父类cast到子类时,父类必须要有虚函数。
回复
arong1234 2008-03-31
这倒没反,CEdit是CWnd的子类
回复
hdqqq 2008-03-31
CWnd* GetDlgItem (
int nID )
const;
返回的就是一个CWnd*

而dynamic_cast一般用于将基类指针转到子类,而你正好反了.
回复
arong1234 2008-03-31
RTTI根据VTBL?VTBL只有几个地址信息怎么会包含这个信息?
回复
stellarguy 2008-03-31
因为RTTI的访问依赖于对象的VTBL ,所以RTTI 只能依赖于 有虚函数的继承关系的 类转换。 楼上说的理由并不充分。
期待更好的回答。
回复
arong1234 2008-03-30
RTTI是用于 C++类型中的,而IDC_EDIT1作为一个编辑框的事实实际不是C++相关的信息,而是windows GDI资源的属性,两者没关系的,因此你这种情况只能强制类型转换
回复
相关推荐
发帖
VC/MFC
创建于2007-09-28

1.5w+

社区成员

VC/MFC相关问题讨论
申请成为版主
帖子事件
创建了帖子
2008-03-30 11:55
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……