考虑以下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();
}
但是,看起来这个设计不会编译,因为模板变量不存在。
在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不起作用,因为:
所以来自第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]
答案 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();
}