对于我想要的东西是否有更好的API

时间:2016-04-02 17:01:22

标签: c++ templates inheritance

考虑以下2个片段:

  1. 这就是我之后的事情:
  2. database.h:

    template<class T, class T2> class __declspec(dllexport) Database
    {
    protected:
        struct Impl;
        Impl *pimpl;
        virtual int GetTableListFromDb(std::vector<T2> &errorMsg) = 0;
    public:
        virtual ~Database() = 0;
        Impl &GetTableVector() { return *pimpl; };
        virtual int Connect(T *selectedDSN, std::vector<T2> &errorMsg) = 0;
        virtual int Disconnect(std::vector<T2> &errorMsg) = 0;
    };
    
    template<class T, class T2> struct Database<T, T2>::Impl
    {
        std::vector<Table> m_tables;
    };
    
    template<class T, class T2> Database<T, T2>::~Database()
    {
        delete pimpl;
    }
    

    在sqlite_db.h中:

    template <class T, class T2> class __declspec(dllexport) SQLiteDatabase : public Database<T, T2>
    {
    public:
        SQLiteDatabase();
        virtual ~SQLiteDatabase();
        virtual int Connect(T *selectedDSN, std::vector<T2> &errorMsg);
        virtual int Disconnect(std::vector<T2> &errorMsg);
    protected:
        void GetErrorMessage(int code, T2 &errorMsg);
        virtual int GetTableListFromDb(std::vector<T2> &errorMsg);
    private:
        sqlite3 *m_db;
    };
    

    在odbc_db.h中:

    template<class T, class T2> class __declspec(dllexport) ODBCDatabase : public Database<T, T2>
    {
    public:
        ODBCDatabase();
        virtual ~ODBCDatabase();
        virtual int Connect(T *selectedDSN, std::vector<T2 *> &errorMsg);
        virtual int Disconnect(std::vector<T2> &errorMsg);
    protected:
        int GetErrorMessage(std::vector<T> &errorMsg);
        virtual int GetTableListFromDb(std::vector<T2> &errorMsg);
    private:
        SQLHENV m_env;
        SQLHDBC m_hdbc;
        SQLHSTMT m_hstmt;
        SQLHWND m_handle;
    };
    

    用法 - 在某些dll中:

    extern "C" __declspec(dllexport) Database *my_dllfunc()
    {
        Database<T, T2> *db = NULL;
        if( <cond1> )
        {
            db = new SQLiteDatabase<const char *, wstring>();
        }
        if( <cond2> )
        {
            db = new ODBCDatabase<SQLWCHAR *, SQLWCHAR*>();
        }
        db->Connect();
    }
    

    在主要应用程序中:

    class CMainFrame
    {
    public:
        CMainFrame();
        ~CmainFrame();
        void Foo();
    private:
        Database *m_pdb;
    }
    
    CMainFrame::CMainFrame()
    {
        m_pdb = NULL;
    }
    
    CMainFrame::~CMainFrame()
    {
        delete m_pdb;
        m_pdbc = NULL;
    }
    
    void CMainFrame::Foo()
    {
        HMODULE instance = ::LoadLibrary( "my_dll" );
        MYFUNC func = (MYFUNC)::GetProcInstance( "my_dllfunc", instance );
        m_pdb = func();
    }
    

    但是,看起来这个设计不会编译,因为模板变量不存在。

    1. 这是我想避免的:
    2. 在database.h中:

      class __declspec(dllexport) Database
      {
      protected:
          struct Impl;
          Impl *pimpl;
          virtual int GetTableListFromDb(std::vector<std::wstring> &errorMsg);
          virtual int GetTableListFromDb(std::vector<SQLWCHAR *> &errorMsg);
      public:
          virtual ~Database() = 0;
          Impl &GetTableVector() { return *pimpl; };
          virtual int Connect(const char *selectedDSN, std::vector<std::wstring> &errorMsg);
          virtual int Connect(SQLWCHAR *selectedDSN, std::vector<SQLWCHAR *> &errorMsg);
          virtual int Disconnect(std::vector<T2> &errorMsg) = 0;
      };
      

      在sqlite_db.h中:

      class __declspec(dllexport) SQLiteDatabase : public Database
      {
      public:
          SQLiteDatabase();
          virtual ~SQLiteDatabase();
          virtual int Connect(const char *selectedDSN, std::vector<std::wstring> &errorMsg);
          virtual int Disconnect(std::vector<std::wstring> &errorMsg);
      protected:
          void GetErrorMessage(int code, std::wstring &errorMsg);
          virtual int GetTableListFromDb(std::vector<std::wstring> &errorMsg);
      private:
          sqlite3 *m_db;
      };
      

      在odbc_db中:

      class __declspec(dllexport) ODBCDatabase : public Database
      {
      public:
          ODBCDatabase();
          virtual ~ODBCDatabase();
          virtual int Connect(SQLWCHAR *selectedDSN, std::vector<SQLWCHAR *> &errorMsg);
          virtual int Disconnect(std::vector<SQLWCHAR *> &errorMsg);
      protected:
          int GetErrorMessage(std::vector<SQLWCHAR *> &errorMsg);
          virtual int GetTableListFromDb(std::vector<SQLWCHAR *> &errorMsg);
      private:
          SQLHENV m_env;
          SQLHDBC m_hdbc;
          SQLHSTMT m_hstmt;
          SQLHWND m_handle;
      };
      

      用法 - 可能是这样的(?):

      在某些dll中:

      extern&#34; C&#34; __declspec(dllexport)数据库* my_dllfunc() {     数据库* db;     if()         db = new SQLiteDatabase();     if()         db = new ODBCDatabase(); }

      在主要应用中:

      class CMainFrame
      {
      public:
          CMainFrame();
          ~CmainFrame();
          void Foo();
      private:
          Database *m_pdb;
      }
      
      CMainFrame::CMainFrame()
      {
          m_pdb = NULL;
      }
      
      CMainFrame::~CMainFrame()
      {
          delete m_pdb;
          m_pdbc = NULL;
      }
      
      void CMainFrame::Foo()
      {
          HMODULE instance = ::LoadLibrary( "my_dll" );
          MYFUNC func = (MYFUNC)::GetProcInstance( "my_dllfunc", instance );
          m_pdb = func();
      }
      

      除了&#34;数据库&#34;对于每个需要的函数,类都会变得不必要地膨胀,然后m_pdb破坏就会崩溃,我只能用简单的代码重现它。

      我在我的GUI中使用wxWidgets,并且可以在那里重现。

      希望现在你能看到我正在寻找的东西。

      它看起来像我放入1`。即使在C ++ 11中也是不可能的。那么,现在,问题变成了 - 可以用什么API来实现它?

      基本上我正在寻找一组类来处理使用不同API的不同数据库。

      作为一个例子,我使用了SQLite和ODBC。

      TIA!

      [编辑]

      API#2不起作用,因为:

      1. 类数据库位于.dll / .a库中(即静态链接)。
      2. 类SQLiteDatabase和ODBCDatabase位于其自己的.dll / .so / .dylib内(即动态链接)。它们链接到database_dll。
      3. 将database_dll链接到主应用程序没有多大意义。因此,Database类成为具有一堆纯虚函数的Database类接口。这意味着现在尝试实现SQLiteDatabase,我需要在odbc32.lib中链接,这是完全没必要的。
      4. 我使用wxWidgets来实现GUI。这是C ++库,并不像MFC那样使用malloc()/ free()进行内存管理。因此,尝试在DLL内部分配内存并在主应用程序内释放将会崩溃。我有一个完整的代码,包括MFC和wx - 第一个工作,第二个 - 不是。我使用的是MSVC 2010 MFC版本和最新稳定的wx版本 - 3.1。
      5. 所以来自第2点的所有API都不起作用。

        [/编辑]

        [EDIT2]

        静态DLL:

        class Database
        {
        public:
            Database();
            ~Database();
            int Connect();
            int Disconnect();
        };
        

        动态DLL1:

        class SQLiteDatabase : public Database
        {
        public:
            SQLiteDatabase();
            ~SQLiteDatabase();
            int Connect();
            int Disconnect();
        };
        

        动态DLL2:

        class ODBCDatabase : public Database
        {
        public:
            ODBCDatabase();
            ~ODBCDatabase();
            int Connect();
            int Disconnect();
        };
        

        这是我追求的界面。静态库Database类代码应该只在头文件中,所以不要显式链接到主应用程序。如何处理SQLite和ODBC操作的不同数据类型?

        我实际上在寻找比这更好的东西:

        class __declspec(dllexport) Database
        {
        public:
            Database();
            ~Database();
            int Connect(const char *dbName, std::vector<std::wstring> &errorMsg) = 0;
            int Connect(SQLWCHAR *dbName, std::vector<SQLWCHAR *> &errorMsg) = 0;
        // possibly more Connect() overwrites
            int Disconnect() = 0;
        };
        

        并且这个界面很难看,因为需要维护所有这些Connect()函数。

        此外,现在SQLite接口现在必须引入odbc库,它不应该依赖它,因为第二个纯虚拟Connect()必须在任何地方实现。

        那还有更好的东西吗?

        [/编辑]

        [EDIT3]

        我使用了xvan&#39;建议,现在一切都编译 - 至少在Windows上使用MSVC 2010.不幸的是,在运行程序时它会崩溃。

        它的编写方式是我在DLL中分配内存然后将指针传递回主应用程序。然后主应用程序应管理指针并将其发送到另一个DLL或自己使用它。当应用程序结束时,应调用Disconnect()函数并销毁指针(通过析构函数释放内存)。

        现在这个方法的问题是,只要我把指针放在主应用程序中,我就不再有关于这个指针是什么的信息了。这意味着在MSVC调试器中,如果我在主应用程序中打开指针,我不再看到派生类的行,因此删除对象会崩溃。

        我想也许我可以将指针推回到分配它的dll,但这确实也崩溃了,因为对象松散了层次结构并且无法保留它。

        那么有没有办法让它在主应用程序内部不分配内存的情况下工作?

        [/ EDIT3]

1 个答案:

答案 0 :(得分:0)

您需要定义一个通用接口,然后从该接口实现适当的转换功能:

以下代码未经测试。

class Database
{
public:
    virtual ~Database()=0;
    virtual int Connect(std::wstring,std::vector<std::wstring> &) =0;
    virtual int Disconnect()=0;
};


class SQLiteDatabase : public Database
{
public:
    SQLiteDatabase();
    ~SQLiteDatabase();
    int Connect(std::wstring,std::vector<std::wstring> &);
    int Disconnect();
};



int SQLiteDatabase::Connect(std::wstring dbName,std::vector<std::wstring> &errMsg)
{
   std::string sqlite_dbName(dbName.begin(), dbName.end());
   std::vector<std::wstring> &  sqlite_errMsg = errMsg;

   /* Call real connect*/
   real_connect( sqlite_dbName.c_str(), sqlite_errMsg);
   /*              */

   return errMsg.size();
}


class ODBCDatabase : public Database
{
    int SQLiteDatabase::Connect(std::wstring dbName,std::v
public:
    ODBCDatabase();
    ~ODBCDatabase();
    int Connect(std::wstring,std::vector<std::wstring> &);
    int Disconnect();
};


int ODBCDatabase::Connect(std::wstring dbName,std::vector<std::wstring> &errMsg){
    SQLWCHAR * odbc_dbName = dbName.c_str();
    std::vector<SQLWCHAR *> & odbc_errMsg;

    /* Call real connect*/
    real_connect(odbc_dbName, odbc_errMsg);

    /*Not sure if this'll work, but if it doesn't, manually copy strings from odbc_errMsg to errMsg*/
    errMsg = std::move( std::vector<std::wstring>(odbc_errMsg.begin(), odbc_errMsg.end()));
    return  errMsg.size();
    }