转载请注明出处:http://cyc.wiki/index.php/2017/07/14/cpp-case-sqlite3-cpp-2/
永远不要说“精通C++”。
上一篇介绍了怎么用C++的特性优雅地封装SQLite3中的sqlite3_bind_*
函数们。这一篇我们继续来看看怎么优雅地改写sqlite3_column_*
函数们。
Github: SQLiteC++ (SQLiteCpp)
sqlite_column_*
在执行了SQL查询语句后,通过会使用sqlite3_step
函数去逐步遍历查询结果的各行,而获取该行的各列数据的函数就是sqlite3_column_*
。我们还是取上一篇的例子,假设数据表中第1列是int类型,第2列是double类型,第3列是字符串类型。
C API
const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
double sqlite3_column_double(sqlite3_stmt*, int iCol);
int sqlite3_column_int(sqlite3_stmt*, int iCol);
sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
int sqlite3_column_type(sqlite3_stmt*, int iCol);
sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
C API依然是这么简单粗暴,还是每一种类型的数据对应一个API的命名,但不同的是这一回所有函数的参数列表都一模一样,仅仅是返回值不同。还记得上一篇提到函数重载的实现本质上是由于参数列表被加进了函数签名,因此如果还想对不同的类型使用同样的函数就不能使用函数重载的方法了。
那怎么办呢?我们可以使用一个统一的中间的对象接收sqlite3_stmt*
和int iCol
两个参数,然后利用类型转换操作符根据不同的类型调用不同的C API获取对应的数据,完成到目标类型的转换。
我不想记住函数的名称 - 类型转换操作符
我们来看SQLiteCpp中是怎么实现自动获取相应类型的结果的。
假设我们已经调用过sqlite3_step
将游标移到了当前结果行,现在我们调用stmt.getColumn(index)
获得一个Column对象:
Column Statement::getColumn(const int aIndex)
{
checkRow();
checkIndex(aIndex);
// Share the Statement Object handle with the new Column created
return Column(mStmtPtr, aIndex);
}
这个函数的内容很简单,除了一些合法检查,就是构造了一个Column对象并返回,Column