Абстрактный класс и множественное наследование
От: Gregory Россия ICQ 300403361
Дата: 18.01.19 11:02
Оценка:
Bonjour, messieurs!

Возникла следующая проблема,заключающаяся в непредсказуемом поведении компилятора VC++.
Есть три класса:


class Father
{
// ....
};

class Mother
{
//......
    virtual void foo() = 0;
//......  
};

class Daughter : public Father, public Mother
{
//.........
  void foo() override;  
};

void Daughter::foo()
{
//....
}


При попытке вызвать Daughter::foo все рушится. Как следует из просмотра asm-листинга, в vftable там, где по идее должен был бы находится адрес Daughter::foo, находится непонятно что. Выглядит вызов следующим образом:

  mov         ecx, dword ptr [this]  
  add         ecx, sizeof(Father)  
  mov         eax, dword ptr [this]  
  mov         edx, dword ptr [eax+sizeof(Father)]  
  mov         eax, dword ptr [edx+offsetof(foo)]  
  call        eax


Выглядит все вроде бы правильно, но при просмотре в дебагере видно, что в eax оказывается вовсе не адрес Daughter::foo. С точки зрения синтаксиса вроде бы тоже все правильно. Что это, глюк компилятора?
Не дай своим глазам увидеть, а ушам услышать то, что ты не сможешь объяснить.
Абрахам ван Хелсинг
Re: Абстрактный класс и множественное наследование
От: LaptevVV Россия  
Дата: 18.01.19 11:21
Оценка:
G>При попытке вызвать Daughter::foo все рушится.
Не понял. Ты метод как метод класса вызываешь? Виртуальный?
Где объект или указатель на объект, от которого метод должен вызывать?
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[2]: Абстрактный класс и множественное наследование
От: Gregory Россия ICQ 300403361
Дата: 18.01.19 11:27
Оценка:
Здравствуйте, LaptevVV, Вы писали:

LVV>Не понял. Ты метод как метод класса вызываешь? Виртуальный?

Как виртуальный. Если конкретно вызывать Daughter::foo, то все конечно замечательно.
LVV>Где объект или указатель на объект, от которого метод должен вызывать?
Это не принципиально, поэтому я опустил эти подробности для краткости изложения. И к тому же из ассемблера это понятно.
Не дай своим глазам увидеть, а ушам услышать то, что ты не сможешь объяснить.
Абрахам ван Хелсинг
Отредактировано 18.01.2019 11:29 Gregory . Предыдущая версия .
Re: Абстрактный класс и множественное наследование
От: kov_serg Россия  
Дата: 18.01.19 11:28
Оценка:
Здравствуйте, Gregory, Вы писали:

G>При попытке вызвать Daughter::foo все рушится. Как следует из просмотра asm-листинга, в vftable там, где по идее должен был бы находится адрес Daughter::foo, находится непонятно что. Выглядит вызов следующим образом:


G>
G>  mov         ecx, dword ptr [this]  
G>  add         ecx, sizeof(Father)  
G>  mov         eax, dword ptr [this]  
G>  mov         edx, dword ptr [eax+sizeof(Father)]  
G>  mov         eax, dword ptr [edx+offsetof(foo)]  
G>  call        eax
G>

Вы что-то не договариваете. Вы вы зываете foo из метода 4-го класса кторый наследуется от Дочери.
Видимо проблема в преобразовании типов, а не в приведённом коде.
У меня генерит примерно такой же код:
00411643  mov         ecx,dword ptr [this] 
00411646  add         ecx,4 
00411649  mov         eax,dword ptr [this] 
0041164C  mov         edx,dword ptr [eax+4] 
0041164F  mov         esi,esp 
00411651  mov         eax,dword ptr [edx] 
00411653  call        eax

И всё работает штатно.
Re[2]: Абстрактный класс и множественное наследование
От: Gregory Россия ICQ 300403361
Дата: 18.01.19 11:36
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Вы что-то не договариваете. Вы вы зываете foo из метода 4-го класса кторый наследуется от Дочери.

_>Видимо проблема в преобразовании типов, а не в приведённом коде.

Вовсе нет. На самом деле приведенный asm — это вызов foo из другого метода дочки.
Если вызвать так:
    Daughter d;
    d.foo();


результат будет тот же.
Не дай своим глазам увидеть, а ушам услышать то, что ты не сможешь объяснить.
Абрахам ван Хелсинг
Re: Абстрактный класс и множественное наследование
От: rg45 СССР  
Дата: 18.01.19 11:39
Оценка: 1 (1) +2
Здравствуйте, Gregory, Вы писали:

G>Возникла следующая проблема,заключающаяся в непредсказуемом поведении компилятора VC++.

G>Есть три класса:
G>При попытке вызвать Daughter::foo все рушится. Как следует из просмотра asm-листинга, в vftable там, где по идее должен был бы находится адрес Daughter::foo, находится непонятно что. Выглядит вызов следующим образом:
G>Выглядит все вроде бы правильно, но при просмотре в дебагере видно, что в eax оказывается вовсе не адрес Daughter::foo. С точки зрения синтаксиса вроде бы тоже все правильно. Что это, глюк компилятора?

Я попробовал доработать исходный пример и запустил его на Visual Studio 2015 и на GCC-6.3, никаких проблем не обнаружил:

https://ideone.com/TbjBEN.

Поэтому для начала хотелось бы понимать, о какой версии студии идет речь, а так же увидеть минимальный рабочий пример, воспроизводящий проблему.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 18.01.2019 11:39 rg45 . Предыдущая версия .
Re: Абстрактный класс и множественное наследование
От: Vamp Россия  
Дата: 18.01.19 11:59
Оценка: +2
>Что это, глюк компилятора?
Нет, это глюк твоей программы. А где именно — без твого кода не известно.
Да здравствует мыло душистое и веревка пушистая.
Re[2]: Абстрактный класс и множественное наследование
От: Gregory Россия ICQ 300403361
Дата: 18.01.19 12:05
Оценка: +1
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, Gregory, Вы писали:


R>Я попробовал доработать исходный пример и запустил его на Visual Studio 2015 и на GCC-6.3, никаких проблем не обнаружил:


R>https://ideone.com/TbjBEN.


R>Поэтому для начала хотелось бы понимать, о какой версии студии идет речь, а так же увидеть минимальный рабочий пример, воспроизводящий проблему.


VS 2012
В этом упрощенном виде пример действительно работает. Конкретный код сюда тащить не хочется. Он большой и навороченный. Я попробую смоделировать ситуацию в более простом виде и отпишусь.
Не дай своим глазам увидеть, а ушам услышать то, что ты не сможешь объяснить.
Абрахам ван Хелсинг
Re[2]: Абстрактный класс и множественное наследование
От: Gregory Россия ICQ 300403361
Дата: 18.01.19 12:08
Оценка:
Здравствуйте, Vamp, Вы писали:

>>Что это, глюк компилятора?

V>Нет, это глюк твоей программы. А где именно — без твого кода не известно.

Почему ты так уверен? Никогда с глюками компилятора не сталкивался, особенно при оптимизации?
Не дай своим глазам увидеть, а ушам услышать то, что ты не сможешь объяснить.
Абрахам ван Хелсинг
Re[3]: Абстрактный класс и множественное наследование
От: rg45 СССР  
Дата: 18.01.19 12:12
Оценка: +4
Здравствуйте, Gregory, Вы писали:

G>VS 2012

G>В этом упрощенном виде пример действительно работает. Конкретный код сюда тащить не хочется. Он большой и навороченный. Я попробую смоделировать ситуацию в более простом виде и отпишусь.

Признаться, примерно такого ответа я и ожидал

По моему опыту, когда что-то падает, но не воспроизводится на простом примере, проблема обычно кроется совсем не там, где кажется на первый взгляд. Скорее всего, какое-то UB в программе — неинициализированные переменные, заезды по памяти, неправомерные static- и reintepret_cast-ы, пр., и др., и т.п.
--
Справедливость выше закона. А человечность выше справедливости.
Re[4]: Абстрактный класс и множественное наследование
От: Gregory Россия ICQ 300403361
Дата: 18.01.19 12:51
Оценка: +1 :)
Здравствуйте, rg45, Вы писали:

R>Признаться, примерно такого ответа я и ожидал


R>По моему опыту, когда что-то падает, но не воспроизводится на простом примере, проблема обычно кроется совсем не там, где кажется на первый взгляд. Скорее всего, какое-то UB в программе — неинициализированные переменные, заезды по памяти, неправомерные static- и reintepret_cast-ы, пр., и др., и т.п.


Ну да, вы совершенно правы. Я проглядел, что в результате множественного наследования случилась diamond problem. А когда стал упрощать код, чтобы локализовать ошибку, сразу ее заметил.
Не дай своим глазам увидеть, а ушам услышать то, что ты не сможешь объяснить.
Абрахам ван Хелсинг
Re[3]: Абстрактный класс и множественное наследование
От: Vamp Россия  
Дата: 18.01.19 13:04
Оценка: +3
G>Почему ты так уверен? Никогда с глюками компилятора не сталкивался, особенно при оптимизации?
Глюки компилятора при оптимизации — это баги (неопределенное поведение) в твоей программе. Чем скорее ты это поймешь, ием лучше для тебя. У компиляторов, конечно, бывают баги, но они так не проявляются.
Да здравствует мыло душистое и веревка пушистая.
Re[5]: Абстрактный класс и множественное наследование
От: Erop Россия  
Дата: 18.01.19 18:27
Оценка:
Здравствуйте, Gregory, Вы писали:

G>Ну да, вы совершенно правы. Я проглядел, что в результате множественного наследования случилась diamond problem. А когда стал упрощать код, чтобы локализовать ошибку, сразу ее заметил.


Ну и хорошо, что всё работает!
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.