将 AfxGetMainWnd 上的 C 样式系列转换从 VC6/MFC6 转换为在现代 MFC 版本(VC++2008 及更高版本)中运行

Posted

技术标签:

【中文标题】将 AfxGetMainWnd 上的 C 样式系列转换从 VC6/MFC6 转换为在现代 MFC 版本(VC++2008 及更高版本)中运行【英文标题】:Converting C-style series of casts on AfxGetMainWnd from VC6/MFC6 to operate in modern MFC version (VC++2008 and later) 【发布时间】:2012-12-02 17:44:50 【问题描述】:

我从 Visual C++ 6.0 移植到 VC++2008 中的 MFC 版本的应用程序,对它进行了很多 get-AfxGetMainWnd()-and-do-C-Style-casts,如下所示:

  CUserInterfaceDoc *m_pDoc = (CUserInterfaceDoc*)((CFrameWnd *)AfxGetMainWnd())
                            ->GetActiveDocument();

当我尝试上述步骤时,只需转换为dynamic_cast<>,我发现在我的程序中不再可以通过 cast-to-a-CUserInterfaceDoc 访问主窗口。我认为可能是 MFC 在 VC++ 6 中滥用了强制转换,或者编译器做了一些魔术。

重写上面的代码以使用动态转换会像这样,它以一个 nil 指针结束,它会触发我在这里写的 assert() 条件,正如我想要的那样:

CUserInterfaceDoc *m_pDoc;
CWnd * mainWnd = AfxGetMainWnd();
assert(mainWnd);
CFrameWnd *frmWnd = dynamic_cast<CFrameWnd *> (mainWnd);
assert(frmWnd);
m_pDoc = dynamic_cast<CUserInterfaceDoc *> (frmWnd);
assert(m_pDoc);

我假设以前做过这件事的每个人都能说“是的,当然,他们改变了这种铸造行为......”但我找不到它的文档。

在可能的情况下,我正在更改我的 C++ 类,以便在我存储的地方拥有一个成员变量(字段) 链接到它以前通过从“或多或少全球”AfxMainWnd() 走下来找到的东西。

这会帮助我知道发生了什么变化,这样我就可以理解上面发生了什么。

CUserInterfaceDoc 是我的应用程序的 MFC C++ Document 类,它是一个 COleServerDoc,它曾经在运行时“可找到”,顶部是粗略的 C 风格。

上面的转换仍然可以在现代 C++ 中编译,但它被破坏了,可能是因为旧的 VC++ 6 编译器使用 C 样式转换执行了某种内部“魔术”,这违反了 ISO C++ 标准。 (这纯粹是我的猜测)。

我的问题分为两部分:

    从另一个当前没有引用主 CFrameWnd 并且一直使用我在此问题顶部显示的 hack 的类中获取 CurrentDocument (CFrameWnd::CurrentDocument) 的常用方法是什么?

    在不符合 ISO 标准的 VC++ 6 和或多或少符合 ISO 标准的 C++ 版本之间发生了哪些变化,这些变化会改变上述转换表达式的行为,或者是否由于 MFC 内部架构变化?

我的代码更改:

CUserInterfaceDoc * CMyBrowser::GetUserInterfaceDoc()

    CUserInterfaceDoc *m_pDoc;
    // formerly did this, which works in VC++6 and doesn't work anymore:
    //m_pDoc = (CUserInterfaceDoc*)((CFrameWnd *)AfxGetMainWnd())->GetActiveDocument();
    assert(m_pMainFrm);
    m_pDoc = dynamic_cast<CUserInterfaceDoc *> ( m_pMainFrm->GetActiveDocument() );
    assert(m_pDoc);

【问题讨论】:

【参考方案1】:

如果您使用的是 MFC,您不妨硬着头皮使用 DYNAMIC_DOWNCAST,它是 MFC 定义的用于投射的宏,基本上等同于 dynamic_cast。

CFrameWnd* pFrm = DYNAMIC_DOWNCAST(CFrameWnd, AfxGetApp()->m_pMainWnd);

m_pDoc = DYNAMIC_CAST(CUserInterfaceDoc, m_pMainFrm->GetActiveDocument());

【讨论】:

这种用法是否仍然被认为是“可接受的”,还是上述被认为是 MFC 的错误功能? 如果您使用 MFC,您应该这样做。对于派生自 CObject 的类,它利用了 MFC 框架中固有的运行时类型信息。 谢谢。这正是我所需要的。 现在似乎更有可能的是编译器 RTTI 是更好、更安全的操作方式。 我会坚持使用 MFC 源代码中仍然遵循的方式。【参考方案2】:

在你的第一次重写中:

CUserInterfaceDoc *m_pDoc;
CWnd * mainWnd = AfxGetMainWnd();
assert(mainWnd);
CFrameWnd *frmWnd = dynamic_cast<CFrameWnd *> (mainWnd);
assert(frmWnd);
m_pDoc = dynamic_cast<CUserInterfaceDoc *> (frmWnd);
assert(m_pDoc);

...您只是错过了 C-Style 演员表中的 GetActiveDocument() 调用。所以它应该像这样工作:

CUserInterfaceDoc *m_pDoc;
CWnd * mainWnd = AfxGetMainWnd();
assert(mainWnd);
CFrameWnd *frmWnd = dynamic_cast<CFrameWnd *> (mainWnd);
assert(frmWnd);    
m_pDoc = dynamic_cast<CUserInterfaceDoc *> (frmWnd->GetActiveDocument());
assert(m_pDoc);

DYNAMIC_DOWNCAST 非常老派,如果您启用 RTTI(默认情况下启用),实际上不再需要它。 另见:MFC DYNAMIC_DOWNCAST vs. dynamic_cast

【讨论】:

接受了这个答案,因为 2012 年的答案似乎已经过时了,其他人可能会过来并找到这个更好的建议。

以上是关于将 AfxGetMainWnd 上的 C 样式系列转换从 VC6/MFC6 转换为在现代 MFC 版本(VC++2008 及更高版本)中运行的主要内容,如果未能解决你的问题,请参考以下文章

Qt入门系列开发教程QSSqss样式

滚动条基本样式设置

Body 元素上的 Vue JS 样式绑定

移动端iPhone系列适配问题

深入理解脚本化CSS系列第四篇——脚本化样式表

Java FX:粗体和斜体样式未应用于某些字体系列