具有多重继承的消息映射 MFC:如何避免警告 C4407 和运行时崩溃

2022-01-12 00:00:00 multiple-inheritance visual-c++ c++ mfc

我最近将一个项目从 VS2008 移植到 VS2013 并遇到了一些堆栈损坏问题.经过一番研究,我可以查明以下代码的原因:

I recently ported a project from VS2008 to VS2013 and ran into some stack corrupt issues. After some research I could pinpoint the cause to the following code:

class CInternalInterface
{
  afx_msg void OnMouseMove(UINT, CPoint) = 0; 
};
class CMyDlg : public CDialog, public CInternalInterface
{
  afx_msg void OnMouseMove(UINT, CPoint); 
}
BEGIN_MESSAGE_MAP(CMyDlg, CDialog)
  ON_WM_MOUSEMOVE()
END_MESSAGE_MAP()

编译器在 ON_WM_MOUSEMOVE() 语句和运行时堆栈中发出 警告 C4407:在指向成员表示的不同指针之间强制转换,编译器可能生成不正确的代码"每当处理 WM_MOUSEMOVE 消息时都会损坏.

The compiler issued a "warning C4407: cast between different pointer to member representations, compiler may generate incorrect code" at the ON_WM_MOUSEMOVE() statement and at runtime the stack got corrupted whenever the WM_MOUSEMOVE message was processed.

代码在 VS2008 上运行良好(没有警告,没有运行时问题),尽管我同意在非 CWnd 派生接口中定义 MFC 消息处理函数一开始并不是一个好主意.

The code ran fine with VS2008 (no warning, no runtime issues), although I agree that defining an MFC message handler function in a non-CWnd-derived interface wasn't a good idea in the first place.

现在我通过为 OnMouseMove 处理程序使用不同的函数名称显式扩展 ON_WM_MOUSEMOVE 来解决它

For now I resolved it by expanding the ON_WM_MOUSEMOVE explicitely using a different function name for OnMouseMove handler

...
class CMyDlg : public CDialog, public CInternalInterface
{
  afx_msg void OnCWndMouseMove(UINT, CPoint); 
  afx_msg void OnMouseMove(UINT, CPoint); 
}
BEGIN_MESSAGE_MAP(CMyDlg, CDialog)
  {
    WM_MOUSEMOVE, 0, 0, 0, AfxSig_vwp, 
     (AFX_PMSG)(AFX_PMSGW) 
     (static_cast< void (AFX_MSG_CALL CWnd::*)(UINT, CPoint) >(&CMyDlg::OnCWndMouseMove))
  },    
END_MESSAGE_MAP()

然而,此解决方案有几个缺点 - 扩展宏可能会导致与未来 MFC 版本不兼容,并且可能会使其他开发人员混淆 MFC 消息处理程序使用不同的名称.

This solution however has several drawbacks - expanding the macro may cause incompatibilities with future MFC versions and it may confuse other developers to have the MFC message handler using a different name.

所以我有两个问题:

  1. 这是编译器错误吗?只要 CWnd 派生的基类是类定义中列出的第一个基类,多重继承不应该与 MFC 一起使用吗?该宏将函数显式转换为 CWnd::*,因此两个 OnMouseMove(...) 函数之间不应有歧义.

  1. Is this a compiler error ? Isn't multiple inheritance supposed to work with MFC as long as the CWnd derived base class is the first one listed in the class definition ? The macro explicitly casts the function to a CWnd::* so there should be no ambiguity between the two OnMouseMove(...) functions.

有没有更好的解决方法?在 CInternalInterface 中重命名 OnMouseMove() 是不可行的,因为它在代码库中大量使用,判断何时调用重命名的函数以及何时在各种实现中使用 OnMouseMove 并非易事.

Is there a better way to resolve it? Renaming the OnMouseMove() in CInternalInterface is not feasible, as it is heavily used in the code base and judging when to call the renamed function and when to use OnMouseMove in the various implementations is not trivial.

推荐答案

只是一种不同的方法.它不能直接解决您使用消息映射的问题.

Just a different approach. It is not solving your problem with the messages maps directly.

为什么不对这样的接口"使用经典的子类化?

Why don't you use classic subclassing for such an "interface"?

我使用 CSubclassWnd(来自 Paul DiLascia)、CHookWnd(来自 PJ Naughter)或仅使用 ATL 子类化功能.

I use CSubclassWnd (from Paul DiLascia), CHookWnd (from PJ Naughter) or just the ATL subclassing features.

这有助于我将接口附加到现有窗口,并且我可以在特定窗口操作上实现标准功能...

This helps me to attach an interface to an existing window and I can implement standard function upon the specific window actions...

使用上述库之一,您甚至可以为一个窗口提供多个接口".

Using one of the libraries above you can even more than one "interface" to a window.

相关文章