2

我正在维护一个遗留的 MFC 应用程序,我看到的模式与Windows 下的面向对象编程中的模式完全一样,其中相关部​​分是:

Persview.h

#ifndef _DEBUG  // debug version in persview.cpp
inline CPersDoc* CPersView::GetDocument()
   { return (CPersDoc*)m_pDocument; }
#endif

Persview.cpp

#ifdef _DEBUG
CPersDoc* CPersView::GetDocument() // non-debug version is inline
{
    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CPersView)));
    return (CPersView*)m_pDocument;
}
#endif //_DEBUG

如果我在互联网上搜索它,我会看到该模式被广泛应用,所以我认为它是向导生成的代码。

我的问题是:在 .h 文件中内联发布版本并在 .cpp 文件中进行调试是否有任何优势或其他充分理由?为什么不将两者放在同一个文件中呢?

4

2 回答 2

2

请注意,您引用的这本书是 1994 年出版的。当时的 C++ 非常不同,而微软的 C++ 编译器则不然。猜测一下,inline当时有不同的语义,并指示编译器内联函数调用,即使在调试配置中也是如此。

除此之外,还有技术原因:编译器只能内联一个函数,如果它看到完整的定义。如果您希望它内联在不同的编译单元中,则函数定义需要在头文件中。另一方面,您不能将非内联函数放在标头中,因为如果标头包含在多个编译单元中,这将违反单一定义规则。在这种情况下,您会收到链接器错误。

如果您希望摆脱代码重复并仍然获得相同的好处,您可以: 只需将调试版本移动到标题中,标记它inline,然后删除预处理器条件。在ASSERT非调试配置中编译为空,编译器可以(可能会)内联函数调用。对于调试配置,编译器不会执行任何优化,并为函数调用发出代码。函数调用在调试配置中是可取的,因为它们会产生更有意义的堆栈跟踪。

于 2018-05-29T22:45:57.297 回答
1

对于非调试版本,优点是头文件恰好是inline函数定义所属的位置,因此 multiple#include只能看到它的一个定义。

对于未内联函数的调试版本,优点是您保持声明和定义分开的约定 - 定义是您希望找到它的地方。

即您不会将它们放在头文件中,因为如果不是,那是出乎意料的inline,并且您不会将它们放在源文件中,因为如果是,那将是错误的inline

于 2018-05-29T12:21:49.953 回答