C++类型转换通用接口设计实现

目录

1.设计思路

2.通用转换接口实现

2.1.抽象基类(统一接口)

2.2.适配器子类(适配不同转换逻辑)

3.使用示例

4.统一接口调用(多转换器管理)

5.设计亮点

6.总结


1.设计思路

在 C++ 中设计通用类型转换接口的核心目标是:屏蔽不同类型、不同转换逻辑的差异,提供统一的转换入口 ,同时支持灵活扩展(如适配成员函数、全局函数、lambda 等转换逻辑)。基于类型擦除(Type Erasure) 和适配器模式,支持任意类型间的转换。

1.抽象接口层:定义统一的转换接口,作为所有转换器的基类,屏蔽具体类型细节。

2.适配器层:通过模板子类适配不同形式的转换逻辑(如成员函数、全局函数、lambda 等),负责具体类型的转换。

**3.类型擦除:**通过模板参数去适配各种不同的参数。

4.类型安全:在适配器中通过严格的类型转换确保输入 / 输出类型匹配,避免未定义行为。

2.通用转换接口实现

2.1.抽象基类(统一接口)

定义 AbstractConverterFunction作为所有转换器的基类,定义统一的转换方法,接收 void* 类型的输入和输出(实现类型擦除),在子类里面去实现这个转换方法。通过统一接口,可在代码中用 AbstractConverterFunction* 指针调用任意类型的转换,无需关心具体转换逻辑的实现细节。

cpp 复制代码
struct AbstractConverterFunction
{
    typedef bool (*Converter)(const AbstractConverterFunction *, const void *, void*);
    explicit AbstractConverterFunction(Converter c = nullptr)
        : convert(c) {}
    AbstractConverterFunction(const AbstractConverterFunction&)=delete;
    AbstractConverterFunction& operator=(const AbstractConverterFunction&)=delete;
    Converter convert;
};

2.2.适配器子类(适配不同转换逻辑)

针对不同形式的转换逻辑(成员函数、带校验的成员函数、函数对象等),实现对应的模板适配器子类,继承 AbstractConverterFunction并实现 Convert 方法。

1.适配普通成员函数(From::toTo() const

当转换逻辑是 From 类的 const 成员函数,且无参数、返回 To 类型时使用。

cpp 复制代码
template<typename From, typename To>
struct ConverterMemberFunction : public AbstractConverterFunction
{
    explicit ConverterMemberFunction(To(From::*function)() const)
        : AbstractConverterFunction(convert),
          m_function(function) {}
    ~ConverterMemberFunction();
    static bool convert(const AbstractConverterFunction *_this, const void *in, void *out)
    {
        const From *f = static_cast<const From *>(in);
        To *t = static_cast<To *>(out);
        const ConverterMemberFunction *_typedThis =
            static_cast<const ConverterMemberFunction *>(_this);
        *t = (f->*_typedThis->m_function)();
        return true;
    }

    To(From::* const m_function)() const;
};
  • 核心作用 :定义转换接口的 "外壳",通过 Converter 函数指针存储具体的转换逻辑(由子类实现)。
  • 类型擦除 :基类本身不依赖模板参数,通过 void* 接收输入 / 输出数据,隐藏了具体的 From/To 类型,使得非模板代码可以统一使用 AbstractConverterFunction* 调用转换。

2.适配带校验的成员函数(From::toTo(bool* ok) const

当转换可能失败(如字符串转数字),成员函数通过 bool* 输出成功标志时使用。

cpp 复制代码
template<typename From, typename To>
struct ConverterMemberFunctionOk : public AbstractConverterFunction
{
    explicit ConverterMemberFunctionOk(To(From::*function)(bool *) const)
        : AbstractConverterFunction(convert),
          m_function(function) {}
    ~ConverterMemberFunctionOk();
    static bool convert(const AbstractConverterFunction *_this, const void *in, void *out)
    {
        const From *f = static_cast<const From *>(in);
        To *t = static_cast<To *>(out);
        bool ok = false;
        const ConverterMemberFunctionOk *_typedThis =
            static_cast<const ConverterMemberFunctionOk *>(_this);
        *t = (f->*_typedThis->m_function)(&ok);
        if (!ok)
            *t = To();
        return ok;
    }

    To(From::* const m_function)(bool*) const;
};
  • 适用场景 :当转换逻辑是 From 类的一个 const 成员函数,且该函数无参数、返回 To 类型时(如 class A { int toInt() const; };,将 A 转换为 int)。
  • 工作原理 :通过模板参数 From/To 捕获具体类型,静态 convert 方法负责将 void* 安全转换为具体类型,再调用存储的成员函数完成转换。

3.适配函数对象(全局函数、lambda、std::function 等)

当转换逻辑是独立的可调用对象(输入 const From&,输出 To)时使用。

cpp 复制代码
template<typename From, typename To, typename UnaryFunction>
struct ConverterFunctor : public AbstractConverterFunction
{
    explicit ConverterFunctor(UnaryFunction function)
        : AbstractConverterFunction(convert),
          m_function(function) {}
    ~ConverterFunctor();
    static bool convert(const AbstractConverterFunction *_this, const void *in, void *out)
    {
        const From *f = static_cast<const From *>(in);
        To *t = static_cast<To *>(out);
        const ConverterFunctor *_typedThis =
            static_cast<const ConverterFunctor *>(_this);
        *t = _typedThis->m_function(*f);
        return true;
    }

    UnaryFunction m_function;
};
  • 适用场景 :转换逻辑是独立的函数(非成员函数)、lambda 表达式或其他函数对象(如 std::function<To(From)>)。
  • 灵活性 :支持任意可调用对象,例如 [](const std::string& s) { return s.size(); }(将 std::string 转换为 size_t)。

3.使用示例

假设我们有一个 String 类,需要转换为 intsize_t,可以通过这套体系实现:

cpp 复制代码
#include <string>
#include <cassert>

// 示例类:String
class String {
private:
    std::string m_str;
public:
    String(std::string s) : m_str(std::move(s)) {}
    
    // 成员函数:转换为长度(size_t)
    size_t length() const { return m_str.size(); }
    
    // 带校验的成员函数:转换为 int(类似 QString::toInt)
    int toInt(bool *ok) const {
        try {
            int val = std::stoi(m_str);
            *ok = true;
            return val;
        } catch (...) {
            *ok = false;
            return 0;
        }
    }
};

int main() {
    // 1. 使用 ConverterMemberFunction:String → size_t(调用 length())
    ConverterMemberFunction<String, size_t> lenConverter(&String::length);
    String s1("hello");
    size_t len;
    // 调用转换:通过基类指针
    AbstractConverterFunction *converter = &lenConverter;
    bool ok = converter->convert(converter, &s1, &len);
    assert(ok && len == 5);  // 成功,长度为5


    // 2. 使用 ConverterMemberFunctionOk:String → int(调用 toInt)
    ConverterMemberFunctionOk<String, int> intConverter(&String::toInt);
    String s2("123");
    int num;
    ok = intConverter.convert(&intConverter, &s2, &num);
    assert(ok && num == 123);  // 转换成功

    String s3("abc");  // 无法转换为int
    ok = intConverter.convert(&intConverter, &s3, &num);
    assert(!ok && num == 0);  // 转换失败,num为默认值0


    // 3. 使用 ConverterFunctor:String → std::string(调用 lambda)
    auto strToStdStr = [](const String& s) { 
        return static_cast<std::string>(s);  // 假设String有转换运算符
    };
    ConverterFunctor<String, std::string, decltype(strToStdStr)> functorConverter(strToStdStr);
    std::string stdStr;
    ok = functorConverter.convert(&functorConverter, &s1, &stdStr);
    assert(ok && stdStr == "hello");  // 转换成功

    return 0;
}

4.统一接口调用(多转换器管理)

这套体系的核心价值是通过 AbstractConverterFunction* 统一管理不同类型的转换器,无需关心具体转换逻辑。例如在框架中存储多个转换器,动态调用:

cpp 复制代码
#include <vector>

int main() {
    // 创建多种转换器
    MyString s1("hello"), s2("123");
    std::string str("test");

    // 存储转换器指针(统一为 AbstractConverterFunction*)
    std::vector<AbstractConverterFunction*> converters;
    
    // 添加场景1的转换器(MyString → int,成员函数)
    converters.push_back(new ConverterMemberFunction<MyString, int>(&MyString::toInt));
    // 添加场景2的转换器(MyString → int,带校验)
    converters.push_back(new ConverterMemberFunctionOk<MyString, int>(&MyString::toInt));
    // 添加场景3的转换器(string → size_t,lambda)
    auto lambda = [](const std::string& s) { return s.size(); };
    converters.push_back(new ConverterFunctor<std::string, size_t, decltype(lambda)>(lambda));

    // 动态调用第一个转换器(MyString → int)
    int output1;
    converters[0]->convert(converters[0], &s1, &output1);
    std::cout << "转换器1结果:" << output1 << std::endl; // 5

    // 动态调用第二个转换器(带校验)
    int output2;
    converters[1]->convert(converters[1], &s2, &output2);
    std::cout << "转换器2结果:" << output2 << std::endl; // 123

    // 动态调用第三个转换器(string → size_t)
    size_t output3;
    converters[2]->convert(converters[2], &str, &output3);
    std::cout << "转换器3结果:" << output3 << std::endl; // 4

    // 释放内存
    for (auto c : converters) delete c;
    return 0;
}

5.设计亮点

1.类型擦除 :通过基类 AbstractConverterFunction 屏蔽具体类型(From/To),使得非模板代码可以统一处理任意转换逻辑(只需存储 AbstractConverterFunction* 指针)。

2.多源适配:通过不同子类适配成员函数、带校验的成员函数、函数对象等多种转换源,覆盖大部分转换场景。

3.类型安全 :虽然使用 void* 传递数据,但模板子类在 convert 方法中通过 static_cast 确保类型匹配(前提是使用时输入 / 输出类型与模板参数一致)。

4.轻量灵活:无需继承或虚函数重载,通过函数指针和模板封装转换逻辑,性能接近直接调用。

6.总结

这套代码是一个通用转换框架 ,核心通过 "抽象基类 + 模板子类 + 函数指针" 实现类型擦除,将不同形式的转换逻辑统一到同一接口下。适用于需要在运行时动态切换转换逻辑,或在非模板代码中处理多种类型转换的场景(如 Qt 的属性系统、数据绑定框架等)。使用时只需根据转换逻辑的类型(成员函数、带校验函数、lambda 等)选择对应的子类,即可通过基类指针统一调用。

相关推荐
im_AMBER3 小时前
杂记 15
java·开发语言·算法
Zzz 小生3 小时前
编程基础学习(一)-Python基础语法+数据结构+面向对象全解析
开发语言·python
胡萝卜3.03 小时前
掌握string类:从基础到实战
c++·学习·string·string的使用
江公望4 小时前
通过QQmlExtensionPlugin进行Qt QML插件开发
c++·qt·qml
Syntech_Wuz4 小时前
从 C 到 C++:容器适配器 std::stack 与 std::queue 详解
数据结构·c++·容器··队列
沐知全栈开发4 小时前
Bootstrap4 表格详解
开发语言
CryptoRzz4 小时前
欧美(美股、加拿大股票、墨西哥股票)股票数据接口文档
java·服务器·开发语言·数据库·区块链
Never_Satisfied4 小时前
在JavaScript / HTML中,div容器在内容过多时不显示超出的部分
开发语言·javascript·html
艾莉丝努力练剑5 小时前
【C++STL :stack && queue (一) 】STL:stack与queue全解析|深入使用(附高频算法题详解)
linux·开发语言·数据结构·c++·算法