Base Class Pointer pointing to a Derived Class Object which is a template variable in another class

144 views Asked by At

Sorry if the title is not clear.But, I'll try to explain the problem clearly.


I am working on a c++ and QT using MVC for the application architecture:

enter image description here

- Some description for application structure:

  • Model Section (designed using polymorphism pattern):

    is responsible for database related stuff, It has an IDataBase.h interface and its implementation for sqlite database type.
    IDataBase.h :

    namespace model{
       class IDataBase;
    }
    class IDataBase
    {
    public:
        virtual ~IDataBase(){
            //;
        }
    
        virtual bool connect(const QString &db) = 0;
    
        virtual bool insertData(QMap<QString,QVariant> &queryData, const 
        QString &table) = 0;
    };
    

    sqlitedb.h

    class SqliteDB: public IDataBase
    {
    public:
        SqliteDB();
        ~SqliteDB();
        bool connect(const QString &db)    
        bool insertData(QMap<QString,QVariant> &queryData, const QString &table);
    private:
        QSqlDatabase m_database;
    };
    
  • Controller Section: I am using the template class DataBaseService to manage any type of databases (mysql, sqlite ....).

    DataBaseService.h // template variable is the database type class

    template<class T> 
    class DatabaseService
    {
    public:
        DatabaseService();
        ~DatabaseService();
        bool addProduct(QMap<QString,QVariant> &queryData, const QString &table);
    private:
         std::unique_ptr<IDataBase> m_database;
    };
    

    DataBaseService.cpp

    template<class T>
    DatabaseService<T>::DatabaseService()
    {
        m_database = std::make_unique<T>();
        m_database->connect("db.sqlite");    
    }
    

- The Problem is :

When I try to create a pointer of class DatabaseService with the template variable SqliteDB in main.cpp file :

 DatabaseService<model::SqliteDB> *sqliteDb = new DatabaseService<model::SqliteDB>();

I get This unresolved externals error :

error: LNK2019: unresolved external symbol "public: __cdecl DatabaseService::DatabaseService(void)" (??0?$DatabaseService@VSqliteDB@model@@@@QEAA@XZ) referenced in function main

- My Questions :

  1. what is wrong in my design?
  2. Is there any better way to design the database workflow?

- Edit:
After I Read the links that are provided by Miles Budnek I understood how templates actually works and I know that I have three options to write template class implementation :

  1. Write implementation directly in header file.

  2. write implementation in .cpp file an write explicit instantiations in cpp file.

  3. Write implementation in .tpp file and include it at the end of header file.

So, I used the second method and wrote explicit instantiation for using model::SqliteDB class: at the end of DataBaseService.cpp

    template class DatabaseService<model::SqliteDB>;

This solved the unresolved externals error! But now I have another error when trying to create an IDatabase pointer for SQliteDB object in DataBaseService.cpp in the line:

 m_database = std::make_unique<T>();

Errors :

error: no viable overloaded '='

error: C2679: binary '=': no operator found which takes a right-hand operand of type 'std::unique_ptr>' (or there is no acceptable conversion) with [ T=model::SqliteDB, _Ty=model::SqliteDB ]

0

There are 0 answers