реклама на сайте
подробности

 
 
> полиморфизм в IAR или куда деваются функции, проблема с перегрузкой виртуальной функции
helius
сообщение Mar 30 2009, 11:35
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 17
Регистрация: 25-01-06
Пользователь №: 13 580



EWERM IAR 4.40A, пишу на плюсах (в настройках стоит Ext. Emb. C++)
создаю класс с чисто виртуальной функцией

Код
virtual BYTE classA::Event(BYTE *) = 0;


наследую и в потомках реализовываю эту функцию

Код
BYTE classB::Event(BYTE *)
{
// some code
  return 0;
}


вызов происходит через указатель на базовый класс (хочу полиморфного поведения потомков), при этом для одного из них (из трех) она вызывается, для других двух прога вылетает...
смотрю в map файл линкера и вижу вот такую запись (по этим вызовам происоходит вылет)
-------------------------------------------------------------------------
CODE Segment part 64. NOT NEEDED.
ENTRY ADDRESS REF BY
===== ======= ======
cOPT::Event(unsigned char *)

not allocated function
-------------------------------------------------------------------------
тоже самое для третьего класса (где вызов происходит нормально)
-------------------------------------------------------------------------
CODE
Relative segment, address: 00000444 - 00000D5F (0x91c bytes), align: 2
Segment part 66. Intra module refs: cPCU::__vtbl
ENTRY ADDRESS REF BY
===== ======= ======
cPCU::Event(unsigned char *) 00000445
stack 1 = 00000000 ( 00000028 )
-------------------------------------------------------------------------

Проверял на всех оптимизациях (speed/size)...
Бывали ли такие проблемы? Интерфейс трех классов в одном *.h, Реализация трех классов в одном модуле *.c, хотя врядли это важно...
Догадываюсь что функция которая ни разу не вызывалась может быть заоптимизирована чуть более чем в ноль (вызов только через указатель на базовый класс) но это ведь не камильфо? или я что то не понимаю?

Есть у уважаемого сообщества какие нибудь мысли по этому поводу?

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

стека с запасом, хипа тоже

все это вертится в многопоточной scmRTOS, хотя это я полагаю тоже не столь важно для реализации базовых концепций ООП в С++

из дебагеров - консоль printf(); перед вызовом Obj -> Event(*Val); проверяю указатель на обьект - не нулевой, вполне такой валидный, на сколько я могу судить из его 4байтного значения :D
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов (1 - 6)
Сергей Борщ
сообщение Mar 30 2009, 11:42
Сообщение #2


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(helius @ Mar 30 2009, 14:35) *
из дебагеров - консоль printf(); перед вызовом Obj -> Event(*Val); проверяю указатель на обьект - не нулевой, вполне такой валидный, на сколько я могу судить из его 4байтного значения :D
А если вставить вызовы в самое начало main() и пройтись симулятором? Что перед вызовом читается из vtbl для правильных и неправильных объектов?


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
helius
сообщение Mar 30 2009, 12:06
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 17
Регистрация: 25-01-06
Пользователь №: 13 580



вызов виртуальной функции через базовый класс подразумевает табличку функций для всех потомков, некая virtual table, а так же есть процесс позднего связывания (через эту табличку)... как это реализовано в IAR я, увы, слабо представляю... но полагаю что решение где то здесь

Цитата
Что перед вызовом читается из vtbl для правильных и неправильных объектов?


гм, проверю...

что то при вызове метода обращения к таблице я невижу, зато на предпоследней инструкции прыжок происходит очень далеко в сплошные нули

pPPD[temp] -> Event((BYTE *)temp);

0000AAE4 6822 LDR R2, [R4, #0]
0000AAE6 2100 MOV R1, #0
0000AAE8 6810 LDR R0, [R2, #0]
0000AAEA 6882 LDR R2, [R0, #8]
0000AAEC 6812 LDR R2, [R2, #0]
0000AAEE F003 ; pre BL/BLX
0000AAF0 FA43 BL ??rT_BX_R2 ; 0xDF78

Сообщение отредактировал helius - Mar 30 2009, 12:07
Go to the top of the page
 
+Quote Post
Andy Mozzhevilov
сообщение Mar 30 2009, 21:01
Сообщение #4


Знающий
****

Группа: Свой
Сообщений: 877
Регистрация: 26-01-05
Из: Екатеринбург
Пользователь №: 2 206



Если бы вы до минимума (одного main.cpp) ужали проект, в котором не работает то, о чем вы говорите, можно было бы посмотреть.
А так, такие вещи в отладчике хорошо ловятся. IAR показывает в Watch нормально классы и указатели на vtbl. По указателю можно пойти и посмотреть, что там в действительности лежит.


--------------------
Пасу котов...
Go to the top of the page
 
+Quote Post
helius
сообщение Apr 2 2009, 15:54
Сообщение #5


Участник
*

Группа: Участник
Сообщений: 17
Регистрация: 25-01-06
Пользователь №: 13 580



презабавнейшую вещь я обнаружил:

когда я обьекты создаю на хипе функцией new тогда у меня компиллер начинает ругаться на не перегруженные чисто виртуальные функции! т.е. до использования new он не догадывался о том что обьекты будут создаваться и даже не ругался на отсутствие перегрузки чисто вертуальной функции в потомках... конечно, а зачем? по другому ведь обьекты то нельзя создавать никак!

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

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

вот такие вот грабли =))))

Сообщение отредактировал helius - Apr 2 2009, 16:00
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Apr 2 2009, 17:04
Сообщение #6


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(helius @ Apr 2 2009, 18:54) *
дело в том что я использую malloc потому что мне не нужно "встать" при нехватки памяти, что как раз делает функция new, а обработку исключения я делать не хочу )
В таком случае вам надо действовать так:
Код
#include <new>

class_t pObj = new(nothrow) class_t;

if (pObj == 0)
{
   Памяти не дали.
}
при использовании malloc конструкторы не вызываюся, значит некому скопировать __vtbl в объект, значит __vtbl не используется и не используются все функции, на которые __vtbl указывает. И линкер их спокойно выкидывает.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
helius
сообщение Apr 3 2009, 01:38
Сообщение #7


Участник
*

Группа: Участник
Сообщений: 17
Регистрация: 25-01-06
Пользователь №: 13 580



Цитата
при использовании malloc конструкторы не вызываюся, значит некому скопировать __vtbl в объект, значит __vtbl не используется и не используются все функции, на которые __vtbl указывает. И линкер их спокойно выкидывает.

Все верно! ) Спасибо всем!

Вопрос закрыт.
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 25th June 2025 - 13:29
Рейтинг@Mail.ru


Страница сгенерированна за 0.01753 секунд с 7
ELECTRONIX ©2004-2016