我正在构建一个带有纯虚函数的类,名为Database
。我们的想法是拥有一个处理所有数据库接口(interface)(即:open
和 close
)的类,并且可以在我的业务层上使用。
Database 类将以针对不同数据库的多种“风格”实现,例如 mySqlDatabase 和 OracleDatabase。
我想象数据库
有没有代码的纯虚拟方法 - 只是一个头文件,如下所示:
数据库.hpp
class Database {
public:
Database();
virtual ~Database();
virtual void open(const std::string databasename) = 0;
virtual void open(const std::string databasename, const std::string username, const std::string password) = 0;
virtual void open(const std::string databasename, const std::string schema, const std::string username, const std::string password) = 0;
.
<Other stuff>
.
}
这三个 open
变体是为了支持不同的数据库连接要求,从最简单的(如仅需要文件名的 Sqlite3)到 Oracle(需要所有变量才能连接)。
我对实现有一些疑问(以 Oracle 为例):
a)我是否需要在派生类头文件上再次重新声明虚拟方法,例如:
class OracleDatabase : public Database {
public:
OracleDatabase ();
virtual ~OracleDatabase ();
void open(const std::string databasename);
void open(const std::string databasename, const std::string username, const std::string password);
void open(const std::string databasename, const std::string schema, const std::string username, const std::string password);
}
b) 如何在派生类中构建 open
方法的实现(以 Sqlite3 为例)?
void Sqlite3Database::open(const std::string databasename){
...do some stuff...
}
void Sqlite3Database::open(const std::string databasename, const std::string username, const std::string password) {
...do some stuff...
}
void Sqlite3Database::open(const std::string databasename, const std::string schema, const std::string username, const std::string password) {
...do some stuff...
}
我使用的策略正确吗?我一直在浏览虚拟和纯虚拟策略,并认为这是解决我的问题的最佳方法。
有什么建议/提示吗?
OBS:我来自 C# 世界,所以如果这里有一些误解,我深表歉意。
最佳答案
对于编写查询函数(即所有数据库的相同接口(interface)),纯虚函数是最佳选择。
在这里,您正在尝试编写 open
函数,您可能需要考虑 Factory Design Pattern :您编写数据库时没有任何 open
功能;然后你编写一个函数,例如 static std::unique_ptr<Database> Sqlite3Database::open(/*...*/)
.
使用像您所提倡的那样的虚拟函数并不是一个好主意:无论如何,您有 3 个不同的函数,它们完全依赖于所使用的数据库;更糟糕的是,你的母类依赖于它的子类:要添加具有另一个日志记录方案的新数据库,你必须将函数原型(prototype)添加到 Database
.
另一种方法是使用纯虚函数(最好是 protected
并从构造函数调用以保留 RAII;并遵循 NVI idiom ),该函数将初始化字符串作为参数,例如正如 PDO 使用的那样。与可以从实例化的类型推断出数据库类型并不完全相同,但其想法是保留单个参数,以免出现 open
的多个版本。
(旧答案保留其试图解释的原则)
实际上你可以做得更简单:忘记 open
,然后在 Sqlite3Database::Sqlite3Database(/* ... */)
内完成所有初始化.
因此,举一个您可以执行的操作的示例:
class Database {
public virtual void create(/* ... */) = 0;
// ...
};
class Sqlite3Database : public Database {
Sqlite3Database(string filename);
public virtual void create(/* ... */) override;
// ...
};
class MySqlDatabase : public Database {
MySqlDatabase(int host, short port, string username, string password);
public virtual void create(/* ... */) override;
};
关于c++ - 如何实现不同参数结构的纯虚函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29859228/