C ++ и виртуальные методы переопределяют - PullRequest
2 голосов
/ 16 июня 2010

Извините за этот глупый вопрос, но я не могу найти ответ сам, я слишком новый в C ++: (

class DBObject : public QObject
{
    ...
protected:
    virtual QString tableName() = 0;
};

class DBUserObject : public DBObject
{
    ...
protected:
    virtual QString tableName()  { return "profiles"; };
};

И у меня есть этот код в родительском:

DBObject::DBObject(quint32 id)
    : QObject(0)
{
    ...    

    if (id != 0)
        load(id);
}

bool DBObject::load(quint32 id)
{
    QString query = QString("select %1 from %2 where id = :id")
        .arg(fieldList().join(","))
        .arg(tableName());              <--- here is trouble
    ...
}

Итак, я пытаюсь выполнить:

DBUserObject user(3);

Но в результате я получил ошибку во время выполнения. Почему не "профили"?

Ответы [ 6 ]

15 голосов
/ 16 июня 2010

На основе последующего комментария ОП:

Пользователь DBUserObject (3).Он загружает элемент в свой конструктор.

Если вы имеете в виду конструктор DBObject (а не конструктор DBUserObject), то это ваша проблема.Виртуальные функции не работают внутри конструкторов.Конструкторы запускаются из наименее производного (наиболее базового) класса в наиболее производный (действительный тип).Когда запускается конструктор класса, объект относится только к типу этого класса и ничего более не наследуется.

Другими словами, когда вы создаете DBUserObject, сначала запускается конструктор QObject, а внутриэтот конструктор объект только QObect и ничего более.Затем запускается конструктор DBObject, и внутри этого конструктора объект представляет собой DBObject и ничего более.Наконец, запускается конструктор DBUserObject, и, наконец, объект является DBUserObject.

Так что если вы вызываете load() внутри конструктора DBObject, объект в этой точке только DBObjectи так имеет только DBObject версия загрузки.Это относится аналогично к любой виртуальной функции.

Если вы хотите получить эффект от вызова DBUserObject версии load(), вам нужно будет вызвать ее из конструктора DBUserObject или извнекласс после того, как объект был построен.

Дополнительная информация:

3 голосов
/ 16 июня 2010

Скорее всего, проблема не в указанном вами коде. Вы нарезаете DBObject s? Это может произойти, если вы передадите по значению в функцию, или если вы храните внутри контейнера напрямую (не через указатель).

Другое дело, почему tableName() не является чисто виртуальным в вашем базовом классе?

2 голосов
/ 16 июня 2010

вы можете использовать «чисто виртуальную» функцию, чтобы убедиться, что могут использоваться только подклассы, поскольку базовый класс (DbObject) не имеет имени таблицы.(через унаследованные классы) иметь действительное имя таблицы

пример: virtual QString tableName() = 0;

1 голос
/ 16 июня 2010

Во-первых, используйте Google, чтобы прочитать о «нарезке объектов» в C ++. Легко (но неправильно) нарезать объект в C ++, особенно для новичков: нарезка происходит, если вы передаете объект по значению (что обычно неверно) вместо передачи по ссылке (что обычно верно), например, если вы объявляете параметр типа «DBObject» (неверно) вместо «DbObject &» или «const DbObject &» (справа).

Во-вторых, добавьте следующие операторы в ваш класс DBObject:

class DBObject : public QObject 
{ 
    ... 
protected: 
    virtual QString tableName()  { return ""; }; 
private:
    //non-default, unimplemented copy ctor and assignment operator
    DBObject(const DBObject&);
    DBObject& operator=(const DBObject&);
}; 

Объявление нестандартного, не реализованного копирования и назначения приведет к ошибкам во время компиляции, когда вы пытаетесь передать DBObject по значению: так, третий шаг - исправить эти ошибки, изменив типы параметров для передачи по ссылке. *

0 голосов
/ 16 июня 2010

Кажется, вы здесь не делаете ничего плохого.Вы уверены, что проблема не в вашем методе QString :: arg (...)?

Явно вызовите this-> tableName ();выглядит как проблема компилятора.

- ОБНОВЛЕНИЕ -

На самом деле ваше определение tableName () должно быть

virtual void tableName() const { ... }

Убедитесь, что ваш оператор = для QString равенв порядке (как константной, так и неконстантной версии), может случиться так, что QString, возвращаемая из tableName (), будет временной через стек, и в этом случае будет вызываться оператор = ...

0 голосов
/ 16 июня 2010

Вы не должны встроить виртуальные функции, потому что некоторые компиляторы не могут справиться с этим очень хорошо.

Вы должны переместить реализацию DBObject :: tableName () и DBUserObject :: tableName в файл .cpp..

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...