2010-06-16 4 views
2

Извините за этот глупый вопрос, но я не могу найти ответ на себя, я слишком новый в C++ :(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); 

Но в результате у меня есть ошибки во время выполнения Почему не «профили»

+0

Какой компилятор вы используете, на какой платформе? Изменяется ли результат, если вы перемещаете реализации 'tableName()' в файл cpp, как вы это делали с 'load()'? –

+0

1. gcc на linux и mingw на окнах 2. не изменяется – silent

+0

Вы _really_ выполняете только две строки «пользователь DBUserObject», за которым следует 'user.load (3);'? – Troubadour

ответ

15

основы Последующего замечания ФПА в:

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

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

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

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

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

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

+0

+1 для фактического определения проблемы: виртуальные конструкторы. –

+0

Ничего себе. Он работает, спасибо за помощь и терпение. Извините за всех, я не ожидал, что проблема при использовании конструктора :) – silent

+1

+1 не только для решения, но и для Угадай, что вы сделали. :) – liaK

0

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

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

+0

Тот же результат :( – silent

0

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

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

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

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

virtual void tableName() const { ... } 

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

+0

Пробовал делать только QString tb = tableName() - та же пустая строка. – silent

+0

«это» не работает, «const» тоже не работает :( – silent

+0

убедитесь, что базовая и производная я знаю, что вам нужно посмотреть на класс QString. –

3

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

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

+0

Что такое виртуально-виртуальная функция? Извините снова - я слишком новичок в C++ – silent

+0

@silent: Чистые виртуальные средства что функция не определяет тело.Это делает класс «абстрактным» (хотя это не ключевое слово C++). Это означает, что класс не может быть создан, он просто служит шаблоном, из которого будут выполняться другие классы который затем предоставит тело для чистой виртуальной функции.Он определяется следующим образом: virtual void func() = 0; – PeterK

+0

Спасибо за объяснение, я запомню его – silent

2

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

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

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

+0

Я получаю ошибку времени выполнения на QString tb = tableName(); – silent

+0

Тогда ваша проблема заключается в том, что вы фактически не переопределяете функцию 'tableName' в классе' DBUserObject'. Вы уверены, что то, что вы разместили выше, является точным отражением вашего кода? Убедитесь, что вы не пропустили 'tableName' или добавили классификатор' const', или изменили тип возвращаемого значения, или что-то в этом роде. –

1

Во-первых, использовать 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&); 
}; 

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

+0

Спасибо за нарезку и ссылки, я проверю его сегодня – silent

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