异常:3.0 版本中对异常宏的修改

这是一个高级主题。

在 MFC 3.0 版及更高版本中,异常处理宏已经改为使用 C++ 异常。 本文说明了这些更改将如何影响现有的代码使用宏的行为。

本文涵盖以下主题:

  • 异常类型和 CATCH 宏

  • 重新抛出异常

异常类型和 CATCH 宏

MFC 在早期版本中,宏 CATCH 使用 MFC 运行时类型信息确定异常类型;异常类型是确定的,也就是说,在 catch 处确定了。 如果有 C++ 异常,而异常类型总是由抛出异常对象的类型处确定。 极少数情况下,这将导致抛出对象的指针与抛出对象的类型的不兼容。

下面的示例阐释了 MFC 3.0 版及早期版本之间的差异造成的结果:

TRY
{
   THROW( (CException*) new CCustomException() );
}
CATCH( CCustomException, e )
{
   TRACE( "MFC 2.x will land here\n" );
}
AND_CATCH( CException, e )
{
   TRACE( "MFC 3.0 will land here\n" );
}
END_CATCH

此代码块在版本 3.0有不同表现,因为控件始终传递给第一个 catch 块以匹配异常声明。 抛出表达式表达式的结果。

THROW( (CException*) new CCustomException() );

抛出CException*,即使被构造为CCustomException。 在 MFC 2.5 版及更早版本中的CATCH 使用 CObject::IsKindOf 宏测试运行时的类型。 因为表达式。

e->IsKindOf(RUNTIME_CLASS(CException));

为 true,第一个 Catch 块捕捉异常。 在版本 3.0中,使用 C++ 异常实现许多异常处理的宏,第二个 Catch 块与抛出的 CException匹配。

这样的代码很少见。 当异常对象传递到接受**CException***的另一个函数时,执行“pre-throw”过程,最后抛出异常。

为了解决此问题,则将函数抛出表达式移到调用代码中,在生成异常时,抛出为编译器所知的实际类型的异常。

重新抛出异常

catch 块不会抛出相同异常的指针。

例如,此代码在旧版本有效,但是,在 3.0 版本会有意外结果:

   TRY
   {
      // Do something to throw an exception.
      AfxThrowUserException();
   }
   CATCH( CException, e )
   {
      THROW( e );    // Wrong. Use THROW_LAST() instead
   }
   END_CATCH
}

使用 catch 块的 THROW 删除指针 e,因此外部catch 块将接收了无效的指针。 使用 THROW_LAST 重新抛出 e。

有关更多信息,请参见 异常:捕获和删除异常

请参见

概念

MFC 中的异常处理