Reputation: 182
I am creating a DB interface and having two different database implementation to use this interface
For example:
class DBOptions {
protected:
DBOptions();
};
class SQLliteDBOptions : public DBOptions { bool verySpecificSQLiteOption; };
class MySQLDBOptions : public DBOptions{ bool verySpecificMySQLOption; };
class DBIface {
public:
enum FileMode {
READ = 1,
WRITE = 2,
READWRITE = 3
};
public:
virtual bool connect(char * filename, DBIface::FileMode mode, DBOptions * opt) = 0;
virtual bool disconnect() = 0;
};
class SQLiteDB : public DBIface {
public:
bool connect(char * filename, DBIface::FileMode mode, SQLliteDBOptions * options)
{ std::cout << "connect form sqlite\n"; }
bool disconnect() { std::cout << "disconnect from sqlite\n"; }
};
class MySQLDB : public DBIface {
public:
bool connect(char * filename, DBIface::FileMode mode, MySQLDBOptions * options)
{ std::cout << "connect form mysql\n"; }
bool disconnect() { std::cout << "disconnect from mysql\n"; }
};
int main() {
DBIface * sqlitedb = new SQLiteDB();
SQLliteDBOptions * opt = new SQLliteDBOptions();
sqlitedb->connect("file", DBIface::READ, opt);
return 0;
}
The method connect
in both derived classes are not considered an implementation for the pure method in the parent class. What should I do to resolve this problem?
I want my class to accept the proper DB option instance. I think I can dynamic cast the DB option to the type I need, but I guess this is not the best solution.
Should I create a setter method to set the DB options for each DB implementation?
Upvotes: 1
Views: 93
Reputation: 120059
I would get rid of connect
and disconnect
altogether. This functionality should be moved to constructors and destructors of derived classes, respectively. Each constructor may have different signature and that's perfectly OK since they are not virtual.
This way, if you have an object derived from DBIface
, you can be absolutely sure it is connected.
This solution is compliant with the RAII idiom and therefore can be recommended as the preferred option.
Upvotes: 0
Reputation: 324
You have to declare a method in derived classes that has the same parameters as the pure virtual method connect(). That is, derived classes will be considered abstract classes too unless you override all the pure virtual functions.
I tried the solution proposed by SoronelHaetir. As expected it works, and I think it solves your problem in an elegant way.
class SQLiteDB : public DBIface{
public:
SQLiteDB(SQLliteDBOptions* opt) { pOtps = opt; }
bool connect(char * filename, SQLiteDB::FileMode mode)
{
std::cout << "connect form sqlite\n";
}
bool disconnect() { std::cout << "disconnect from sqlite\n"; }
private:
SQLliteDBOptions * pOtps;
};
int main() {
SQLliteDBOptions * opt = new SQLliteDBOptions();
DBIface * sqlitedb = new SQLiteDB(opt);
sqlitedb->connect("file", DBIface::READ);
return 0;
}
And of course, virtual function in the abstract base class has to be modified accordingly:
virtual bool connect(char * filename, DBIface::FileMode mode) = 0;
Upvotes: 0
Reputation: 15172
I would say make the options parameter an argument to the derived database type's constructor. That way the derived type can require the correct options type without having to worry about matching the base signature. So long as the options parameter is on any virtual method then it has to be the same (or a base type via contravariance).
Upvotes: 2