如何实现不同参数结构的纯虚函数

How to implement pure virtual functions with different parameter structures

我正在构建一个名为 Database 的带有纯虚函数的 class。我的想法是有一个 class 来处理所有数据库接口(即:openclose)并且可以在我的业务层上使用。

数据库 class 将在多个 'flavours' 中针对不同的数据库实施,例如 mySqlDatabase 和 OracleDatabase。

我想象 Database 有没有代码的纯虚拟方法 - 只是一个头文件如下:

Database.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 头文件中再次重新声明虚拟方法,例如:

    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) 如何在派生的 class 中构造 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...
    }

我使用的策略是否正确?我一直在浏览虚拟和纯虚拟策略,认为这是解决我的问题的最佳方法。

任何suggestions/hints?

OBS:我来自 C# 世界,所以如果这里有任何误解,我深表歉意。

对于编写查询函数(即所有数据库的相同接口),纯虚函数是可行的方法。

在这里,您正在尝试编写一个 open 函数,为此您可能需要考虑 Factory Design Pattern:您使用任何 open 编写数据库功能;然后你写了一个函数,比如 static std::unique_ptr<Database> Sqlite3Database::open(/*...*/).

使用像您提倡的那样的虚函数不是一个好主意:无论如何,您有 3 个完全取决于所使用的数据库的不同函数;更糟糕的是,你的母亲 class 依赖于它的 children:要使用另一个日志方案添加一个新数据库,你必须向 Database.

添加一个函数原型

另一种方法是使用纯虚函数(最好是 protected 并从构造函数调用以保留 RAII;并遵循 NVI idiom) that takes as argument an initialization string such as the one used by PDO。与数据库类型不完全相同可以从实例化的类型中推断出来,但想法是保留一个参数,以免有多个版本的 open

(旧答案保留它试图解释的原则)

实际上你可以做得更简单:忘记 open,只在 Sqlite3Database::Sqlite3Database(/* ... */).

中完成所有初始化

毕竟,你无法在不知道它是哪种数据库的情况下打开数据库(因为你必须知道 username/password,甚至更多:你必须知道需要什么参数), 因此尝试从中创建虚拟纯函数是没有意义的。

所以,举个例子说明你可以做什么:

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;
};