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

标签 c++ polymorphism virtual abstract pure-virtual

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

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/

相关文章:

c++ - 如何使用 dlmopen 在不同线程中打开多个共享库?

c++ - 将 std::reference_wrapper<Derived> 视为 std::reference_wrapper<Base> 的最佳方式

c++ - 虚拟覆盖和二进制兼容性

c++ - 这个继承类会调用哪个方法(虚函数)? C++

login - Genymotion凭证。我无法登录 Sprite 运动凭证

c++ - 翻转 map 键值对

c++ - 将 x-1 计算成一个变量然后使用它会更好吗?

c++ - 暂停时编辑轨迹栏值

ruby-on-rails - 如何更改多态模型的外部类型

c++ - C++中堆类的多态性