目录
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
类,需要转换为 int
或 size_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 等)选择对应的子类,即可通过基类指针统一调用。