2010-08-10 4 views
2

У меня проблема с использованием прямого объявления и виртуальных функций. Во время компиляции я получил следующее сообщение об ошибке.C++ Форвардная декларация и чистые виртуальные функции

main.cpp:131: error: cannot allocate an object of abstract type ‘Database::MySQL’ 
database_mysql.h:31: note: because the following virtual functions are pure within ‘Database::MySQL’: 
database.h:28: note: virtual void Database::Interface::query(const char*, QueryResult&) 
database.h:29: note: virtual void Database::Interface::query(std::string, QueryResult&) 
database.h:30: note: virtual bool Database::Interface::step(QueryResult&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&) 

Компилятор сказал, что эти функции по-прежнему являются чистыми виртуальными функциями, но я объявил и определил их правильно. Я не знаю, в чем проблема.

Вот мой исходный код.

// database.h 
class QueryResult; 

namespace Database 
{ 
    class Interface { 
     public: 
      Interface() {}; 
      virtual ~Interface() {}; 

      virtual void query(const char *sql) = 0; 
      virtual void query(std::string sql) = 0; 
      virtual void query(const char *sql, QueryResult &result) = 0; 
      virtual void query(std::string sql, QueryResult &result) = 0; 
      virtual bool step(QueryResult &result, 
           std::vector<std::string> &row) = 0; 
    }; 
} 

// database_mysql.h 
namespace Database 
{ 
    class MySQL : public Interface { 
     public: 
      class QueryResult { 
      public: 
       QueryResult(); 
       ~QueryResult() ; 
       void set(MYSQL_RES *result); 
       MYSQL_RES *get(); 

      private: 
       MYSQL_RES *_result; 

      }; 

      ... 

      void query(const char *sql); 
      void query(std::string sql); 
      void query(const char *sql, QueryResult &result); 
      void query(std::string sql, QueryResult &result); 
      bool step(QueryResult &result, std::vector<std::string> &row); 

      ... 
    }; 
} 


// database_mysql.cpp 
Database::MySQL::QueryResult::QueryResult() 
    : _result(NULL) 
{ 
} 

Database::MySQL::QueryResult::~QueryResult() 
{ 
    ... 
} 

void Database::MySQL::QueryResult::set(MYSQL_RES *result) 
{ 
    ... 
} 

MYSQL_RES *Database::MySQL::QueryResult::get() 
{ 
    ... 
} 


void Database::MySQL::query(const char *sql) 
{ 
    ... 
} 

void Database::MySQL::query(std::string sql) 
{ 
    ... 
} 

void Database::MySQL::query(const char *sql, QueryResult &result) 
{ 
    ... 
} 

void Database::MySQL::query(std::string sql, QueryResult &result) 
{ 
    ... 
} 

/* @return: false on done or true if remained rows exist */ 
bool Database::MySQL::step(QueryResult &result, std::vector<std::string> &row) 
{ 
    ... 
} 

спасибо.

+0

Вы должны показать, что находится на main.cpp: 131, чтобы мы могли вам помочь. Ваш конкретный класс правильно определен, но я подозреваю, что вы не создаете экземпляр объекта правильно. Также, как отметил @anders, ваш класс QueryResult должен принадлежать файлу Interface.h. –

+0

@Edison Gustavo Muenz: эту ошибку можно воспроизвести, пытаясь создать экземпляр класса 'Database :: MySQL' – Naveen

ответ

1

Подведите Децл «QueryResult» в базу данных имен :: Интерфейс

это, кажется, проблема с пространствами имен.

+0

Спасибо за ваш ответ. Однако проблема все еще остается с одинаковыми сообщениями об ошибках. – Brian

3

Из-за форварда декларации компилятор ищет класс QueryResult в глобальном пространстве имен. Функция, которую вы определили в классе MySQL, использует внутренний класс (который находится внутри пространства имен) QueryResult. Это рассматривается как перегрузка компилятором, а не как реализация чистой виртуальной функции. Мое предложение решить это - удалить переднюю декларацию и сделать QueryResult внутренним классом интерфейса Interface (имеет смысл его поместить, иначе интерфейс не нужен). Затем он будет компилироваться правильно.

+0

Спасибо. hmmm ... Я использовал форвардную декларацию, чтобы указать, что существуют разные классы QueryResult, зависит от SQL API, таких как database_sqlite3.h и т. д. Но я думаю, что это невозможно, если я поместил класс QueryResult в класс Interface. – Brian

+0

Возможно, вы можете сделать 'QueryResult' также абстрактным базовым классом, чтобы различная реализация' Interface' могла обеспечить собственную реализацию 'QueryResult'? – Naveen

+0

Спасибо, я попробую сейчас, но как я могу получить различный дескриптор базы данных в параметрах функции-члена абстрактного базового класса? Должен ли я использовать указатель void или класс шаблона? Извините за мой бедный вопрос. Я новичок C++. :-) – Brian

0

Возможно, вы можете быстро исправить ситуацию, сделав QueryResult классом и получив от него MySQLQueryResult. Как отмечали другие, проблема заключается в том, что компилятор не может использовать вложенный класс вместо прямого объявленного класса.

 // database.h 
     class QueryResult { 
     //make this class abstract by creating a protected default constructor 
     protected: 
      QueryResult(){} 
     } 

     //mysql.cpp 
     class QueryResult : ::QueryResult { 
     public: 
      QueryResult(); 
      ~QueryResult() ; 
      void set(MYSQL_RES *result); 
      MYSQL_RES *get(); 

     private: 
      MYSQL_RES *_result; 

     }; 
+0

Можно ли вызвать функции MySQLQueryResult с использованием ссылки QueryResult? Как я могу объявить параметры MySQLQueryResult для функций-членов интерфейса без форвардных объявлений? – Brian

+0

Базовый класс QueryResult должен содержать элементы, которые применимы ко всем реализациям интерфейса, поэтому 'QueryResult' должен содержать наименьшие общие функции/атрибуты знаменателя в нем. –

Смежные вопросы