Russian Qt Forum

Qt => Общие вопросы => Тема начата: dr_Begemot от Март 31, 2010, 11:33



Название: Пропадает виртуальная функция
Отправлено: dr_Begemot от Март 31, 2010, 11:33
Столкнулся с очень странной проблемой...

Есть некий базовый класс, имеющий некую виртуальную функцию. Далее создается порожденный класс с этой же функцией.

Если вызывать эту функцию в конструкторе порожденного класса, то все ок, если сразу после отработки конструктора в функции main вызвать некую функцию test() которая вызывает виртуальный метод, то программа вылетает с ошибкой Unhandled exception at 0x00000000 in Test.exe: 0xC0000005: Access violation reading location 0x00000000.

Если поставить брейк в функции тест на вызове нашего виртуального метода, то видно что он NULL.

Проект достаточно большой и выложить его не могу, но что странно, делаю классы foo и bar по той же схеме что и у меня (упрощенный вариант) - и все ок.
Более того... Базовый класс унаследован от QGLWidget, если его унаследовать от QWidget то все ок. Прототип виртуальной функции
Код:
QRect drawingRect()
В чем может быть дело?

Спасибо)

upd: в конструкторах/деструкторах виртуальные функции ведут себя как обычные
Тогда, в общем, понятно почему в конструкторе все ок, но почему при вызове из метода функция NULL? Как вообще такое может быть??? И в базовом, и в порожденном классах присутствует реализация метода drawingRect.


Название: Re: Пропадает виртуальная функция
Отправлено: niXman от Март 31, 2010, 11:53
Цитировать
Прототип виртуальной функции
это ни разу не виртуальный метод ;)


Название: Re: Пропадает виртуальная функция
Отправлено: dr_Begemot от Март 31, 2010, 11:56
Цитировать
Прототип виртуальной функции
это ни разу не виртуальный метод ;)

Извиняюсь, но это прототип функции ;)
В базовом классе написано конечно же так:
Код:
virtual QRect drawingRect();


Название: Re: Пропадает виртуальная функция
Отправлено: niXman от Март 31, 2010, 12:08
Цитировать
Извиняюсь, но это прототип функции
так мы говорим про функции или методы? не сбивайте с толку!


Название: Re: Пропадает виртуальная функция
Отправлено: dr_Begemot от Март 31, 2010, 12:14
Цитировать
Извиняюсь, но это прототип функции
так мы говорим про функции или методы? не сбивайте с толку!

Вы любите поспорить о несущественном...
Виртуальный метод (http://"http://ru.wikipedia.org/wiki/%D0%92%D0%B8%D1%80%D1%82%D1%83%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4")

Виртуальный метод (виртуальная функция) — в объектно-ориентированном программировании метод (функция) класса, который может быть...


Название: Re: Пропадает виртуальная функция
Отправлено: cya-st от Март 31, 2010, 12:19
В класе функция и метод одно и то же.


Название: Re: Пропадает виртуальная функция
Отправлено: Akaiten от Март 31, 2010, 12:31
Столкнулся с очень странной проблемой...
Если поставить брейк в функции тест на вызове нашего виртуального метода, то видно что он NULL.
Это как понять? Делает call по 0x0?


Название: Re: Пропадает виртуальная функция
Отправлено: Igors от Март 31, 2010, 12:40
upd: в конструкторах/деструкторах виртуальные функции ведут себя как обычные
Тогда, в общем, понятно почему в конструкторе все ок, но почему при вызове из метода функция NULL? Как вообще такое может быть??? И в базовом, и в порожденном классах присутствует реализация метода drawingRect.
В конструкторе базового класса будет вызываться drawingRect базового класса, это нормально.
По поводу NULL ф-ции. Не знаю как Вы увидели что ф-ция NULL - у меня отладчик этого не позволяет  :) Но если так, то

- попробуйте вызвать его явно MyClass::drawingRect()
- если это проходит - где-то Вы замочили указатель на VMT, надо разбираться где напр. вставляя drawingRect в разные места
- если все равно NULL - ну попробовать "Rebuild All" для начала. Потом закомментарить реализацию drawingRect и смотреть что скажет линкер.


Название: Re: Пропадает виртуальная функция
Отправлено: dr_Begemot от Март 31, 2010, 13:18
upd: в конструкторах/деструкторах виртуальные функции ведут себя как обычные
Тогда, в общем, понятно почему в конструкторе все ок, но почему при вызове из метода функция NULL? Как вообще такое может быть??? И в базовом, и в порожденном классах присутствует реализация метода drawingRect.
В конструкторе базового класса будет вызываться drawingRect базового класса, это нормально.
По поводу NULL ф-ции. Не знаю как Вы увидели что ф-ция NULL - у меня отладчик этого не позволяет  :) Но если так, то

- попробуйте вызвать его явно MyClass::drawingRect()
- если это проходит - где-то Вы замочили указатель на VMT, надо разбираться где напр. вставляя drawingRect в разные места
- если все равно NULL - ну попробовать "Rebuild All" для начала. Потом закомментарить реализацию drawingRect и смотреть что скажет линкер.

Столкнулся с очень странной проблемой...
Если поставить брейк в функции тест на вызове нашего виртуального метода, то видно что он NULL.
Это как понять? Делает call по 0x0?

Да :(

Мда... если в порожденном классе drawingRect вызвать явно, то это прокатывает...
Я и rebuild all пробовал, и проект из pro-файла пересобирал...
закомментарить реализацию drawingRect - в смысле совсем закоментарить или тока реализацию??? Боюсь если тока реализацию, то вообще не скомпилиться, разве не так?


Название: Re: Пропадает виртуальная функция
Отправлено: dr_Begemot от Март 31, 2010, 13:30
Если убрать функцию drawingRect() из порожденного класса, но оставить ее в базовом как виртуальную, то программа все равно вылетает на месте вызова drawingRect. Если же убрать virtual из базового класса вообще, то все ок...

Надо отметить, что если drawingRect вызывать явно, т.е писать MyClass::drawingRect то во всех случаях все корректно работает. Видимо проблема с таблицей виртуальных методов... странно только что виртуальные методы типа
Код:
virtual void mouseMoveEvent(QMouseEvent *event);
работают без проблем...

Не представляю как можно отловить такой баг :(


Название: Re: Пропадает виртуальная функция
Отправлено: pastor от Март 31, 2010, 15:24
Выложи минимальный пример, который это воспроизводит


Название: Re: Пропадает виртуальная функция
Отправлено: Igors от Апрель 01, 2010, 05:05
Если убрать функцию drawingRect() из порожденного класса, но оставить ее в базовом как виртуальную, то программа все равно вылетает на месте вызова drawingRect. Если же убрать virtual из базового класса вообще, то все ок...

Надо отметить, что если drawingRect вызывать явно, т.е писать MyClass::drawingRect то во всех случаях все корректно работает. Видимо проблема с таблицей виртуальных методов... странно только что виртуальные методы типа
Код:
virtual void mouseMoveEvent(QMouseEvent *event);
работают без проблем...

Не представляю как можно отловить такой баг :(
Если остальные виртуалы Ок (это лучше перепроверить), то дело хуже - испорчена сама VMT а не указатель на нее. Я бы объявил статический объект (чтобы конструктор вызывался до main) напр.
Код:
static MyClass test;
и в его конструкторе проверил бы drawingRect. 


Название: Re: Пропадает виртуальная функция
Отправлено: dr_Begemot от Апрель 01, 2010, 10:33
Выложи минимальный пример, который это воспроизводит

Проблема в том, что минимальный пример это не воспроизводит...
Код:
#include <QGLWidget>

class B;

class A : public QGLWidget{
Q_OBJECT

friend class B;
public:
A(QWidget* parrent = 0);

virtual void test();
private:
virtual QString drawingRect();
};

class B : public A{
Q_OBJECT

public:
B(QWidget* parrent = 0);

void test();
private:
QString drawingRect();
};

Код:
A::A(QWidget* parrent) : 
QGLWidget( parrent ){//QGLFormat(QGL::SampleBuffers), parent ){
}
void A::test(){
QString val = drawingRect();
}
QString A::drawingRect(){
return QString("A class");
}

B::B(QWidget* parrent) : A(parrent){
}

void B::test(){
A::test();
QString valA = A::drawingRect();
QString val = drawingRect();
}
QString B::drawingRect(){
return QString("B class");
}


Название: Re: Пропадает виртуальная функция
Отправлено: pastor от Апрель 01, 2010, 10:42
В таком случае, запускай свою программу под Valgrind и смотри где бьется память.


Название: Re: Пропадает виртуальная функция
Отправлено: dr_Begemot от Апрель 01, 2010, 10:49
Если убрать функцию drawingRect() из порожденного класса, но оставить ее в базовом как виртуальную, то программа все равно вылетает на месте вызова drawingRect. Если же убрать virtual из базового класса вообще, то все ок...

Надо отметить, что если drawingRect вызывать явно, т.е писать MyClass::drawingRect то во всех случаях все корректно работает. Видимо проблема с таблицей виртуальных методов... странно только что виртуальные методы типа
Код:
virtual void mouseMoveEvent(QMouseEvent *event);
работают без проблем...

Не представляю как можно отловить такой баг :(
Если остальные виртуалы Ок (это лучше перепроверить), то дело хуже - испорчена сама VMT а не указатель на нее. Я бы объявил статический объект (чтобы конструктор вызывался до main) напр.
Код:
static MyClass test;
и в его конструкторе проверил бы drawingRect.  

Вы уверены, что так можно сделать?
Модуль оформлен в виде dll, подключаю его к тесту, и перед main пишу
Код:
static MyClass test;
так?

Если написать:
Код:
int main(int argc, char *argv[]){
    static MyClass test;
    test.drawingRect();
}
то все по прежнему, вылетает...


Название: Re: Пропадает виртуальная функция
Отправлено: BRE от Апрель 01, 2010, 11:02
2 dr_Begemot
Попробуй перенести декларацию функции drawingRect из секции private, в секцию protected.


Название: Re: Пропадает виртуальная функция
Отправлено: Igors от Апрель 01, 2010, 14:42
Я имел ввиду
Код:
static MyClass test;
MyClass::MyClass(.. )
{
    ...
    drawingRect();  // здесь точка останова
}

int main(int argc, char *argv[]){
...
}


Название: Re: Пропадает виртуальная функция
Отправлено: dr_Begemot от Апрель 01, 2010, 15:32
2 dr_Begemot
Попробуй перенести декларацию функции drawingRect из секции private, в секцию protected.


В protected и есть.


Название: Re: Пропадает виртуальная функция
Отправлено: BRE от Апрель 01, 2010, 15:35
В protected и есть.
А здесь опечатка?
Код
C++ (Qt)
class A : public QGLWidget{
       Q_OBJECT
 
       friend class B;
public:
       A(QWidget* parrent = 0);
 
       virtual void test();
private:
       virtual QString drawingRect();
};
 

И объясни для чего ты используешь friend class B; ?