c++ - 如何为遗留 API/框架(C++ 宏 vs. C++ 模板 vs. 代码生成器)实现大量复杂的包装器?

原文 标签 c++ templates macros code-generation legacy-code

我们使用 VC6 编译器在 C++ 中实现的非常古老的遗留系统。现在我们正在重构代码。我们还切换到了 VC9 编译器。

我们使用外部专有框架,该框架也是遗留代码且不可单元测试。为了使我们的代码可进行单元测试,我们为框架类引入了接口(interface)和包装器(提示:请参阅 Martin Fowler 的“使用遗留代码”):

enter image description here

现在我们依赖于接口(interface)。包装器调用框架方法,我们可以在单元测试中愉快地使用模拟。

在这里,我们来解决我们的问题......

框架类包含许多需要包装和模拟的方法。为了实现这一目标,我们的供应商团队编写了一个 API,它使用 C++ 宏生成接口(interface)、包装器和模拟实现。

包装头文件示例:

class PlanWrapper : public IPlan
{
  // ... 
  WRP_DECLARE_DEFAULTS(FrameworkPlan); // macro
  WRP_DECLARE_CSTR_ATTR(FrameworkPlanLabel); // macro
  // ...
};

宏 WRP_DECLARE_CSTR_ATTR 定义如下:
#define WRP_DECLARE_CSTR_ATTR(AttrName) \
    virtual bool set##AttrName (LPCTSTR Value_in); \
    virtual bool get##AttrName (CString& Value_out); \
    virtual bool unset##AttrName (); \
    virtual bool isSet##AttrName ()

包装 cpp 文件示例:
#include "StdAfx.h"

using namespace SomeNamespace;

WRP_IMPLEMENT_MODDICOM_DEFAULTS(FrameworkPlan)
WRP_IMPLEMENT_W_CSTR_ATTR (FrameworkPlan,FrameworkType1, FrameworkPlanLabel)
// ...

宏 WRP_IMPLEMENT_W_CSTR_ATTR 定义如下:
#define WRP_IMPLEMENT_W_CSTR_ATTR(ClassName,AtrTypeObj,AttrName) \
    bool ClassName##Wrapper::set##AttrName (LPCTSTR Value_in) { \
            AtrTypeObj aValue = Value_in; \
        FrameworkLink<ClassName> convertedObj = NULL_LINK; \
        framework_cast(convertedObj, m_Object); \
        return convertedObj != NULL_LINK ? \
                       convertedObj->set##AttrName (aValue) : false; \
    }
    // ...

我们有一堆更复杂的东西,但我想你明白了。

API 的问题在于它极其复杂、不可读、不可调试且不可测试。

我们想提出一个更好的机制来实现同样的目标。这个想法是我们使用新编译器附带的一些高级功能,如高级模板、类型列表、特征等。

使用模板我们几乎可以实现我们的目标,但是我们被方法名称所困扰。我们可以对类型进行泛化,但是我们如何处理属性名称呢?

我们还考虑过创建一个工具来自动生成包装器 + 接口(interface) + 模拟代码。但是,我们外部框架的 API 极其复杂,编写这样一个工具的成本会非常高。

您认为解决此类问题的最佳方法是什么?也许你已经处理过类似的事情并且可以提供很好的提示?我们期待看到您的答案!

最佳答案

我想我会使用代码生成工具。我可能会制作一些简单的实用程序:一个用于生成与遗留框架的类相对应的接口(interface),一个用于生成包装器,另一个用于生成模拟对象(或至少是一个骨架)。

这意味着有一些方法可以解析旧框架的代码。我想看看Clang ,或者干脆运行 ctags在源文件上并处理生成的标签。

关于c++ - 如何为遗留 API/框架(C++ 宏 vs. C++ 模板 vs. 代码生成器)实现大量复杂的包装器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8503457/

相关文章:

c++ - 用于捕获未分配 r 值的编译器选项

c++ - UDP服务器停止接收数据

c++ - 选择性启用模板类功能

c++ - 模板类的std::map类型签名(声明)

macros - 为什么此宏调用会导致名称无法解析?

c++ - #ifdef宏调用中的内容适用于gcc,但不适用于msvc

c++ - 为什么 bool 转换明确提到prvalue

c++ 11模板类型别名以减轻痛苦

iphone - objective-c -以NSDictionary为参数的宏

c++ - 您如何在编译时静态生成float数据?