我想编写一个可以操作不同类型数据库的数据库包装器(例如sqlite,postgres等),因此无论用户实际使用的是什么数据库,用户编写的代码都不会改变。
在我看来,这需要一个抽象的基类,如:
class database {
public:
virtual bool query(const std::string &q) = 0;
// Other stuff
};
class sqlite : public database {
public:
bool query(const std::string &q) {
// Implementation
}
};
这看起来不错,但是我使用可变参数模板来逃避查询中的参数(我真的很喜欢这个想法,所以我想要坚持下去!),所以不幸的是我的基类看起来像:
class database {
public:
template <typename... Args>
bool query(const std::string &q, const Args &... args) {
// Implementation
}
};
这阻碍了创建抽象类,因为模板化函数不能是虚拟的。到目前为止我唯一想到的就是这个构造
template <class DatabaseType>
class database {
public:
template <typename... Args>
bool query(const std::string &q, const Args &... args) {
return database_.query(q, args...);
}
private:
DatabaseType database_;
};
虽然这似乎有效,但所有的包装器除了调用同名的database_
函数之外什么都不做,它对我来说看起来不是一个很好的风格。这是选择的设计模式,还是更清洁,更惯用的方式?
答案 0 :(得分:4)
[...]有更清洁,更惯用的方式
您可能希望查找CRTP以使用模板实现多态行为。
template <class concrete_db>
struct abstract_db {
template <typename... Args>
void query(std::string const& q, Args const&... args) {
static_cast<concrete_db *>(this)->query(q, args...);
}
};
struct postgres_db : abstract_db<postgres_db> {
template <typename... Args>
void query(std::string const& q, Args const&... args) {
// do something
}
};
答案 1 :(得分:4)
您可以从query
函数的参数中构建查询对象,并将其传递给虚拟query_impl
函数。