Войти
ПрограммированиеФорумОбщее

С++ баг!! стандартный или MS-specific ? (2 стр)

Advanced: Тема повышенной сложности или важная.

Страницы: 1 2 3 4 5 6 7 Следующая »
#15
14:36, 7 фев. 2010

Nikopol
> Вероятно дело в этом:
> http://www.parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.13
ты видишь в моем коде C-style downcasts ?


#16
14:45, 7 фев. 2010

upcast

#17
15:05, 7 фев. 2010

Nikopol
> upcast
по твоей ссылке говорилось только про даункаст =)) да и апкаст то работает нормально с этим классом. в проекте я переделал примерно так:

struct base
{
    virtual base* copy() = 0;
};
struct derived : base
{
    virtual base* copy() { return copy(0)}
    virtual derived* copy(int) {}
};
#18
15:18, 7 фев. 2010

Kloun
Вообще, если убрать перегрузку возвращаемого значения

struct ObjectImp : virtual IObject
{
  virtual IObject* create();
то всё замечательно работает.
Что ты в итоге и сделал сам.

Я просто не стал сразу уж тебе это предлагать, думал тебе перегрузка реально нужна.

#19
15:49, 7 фев. 2010

Nikopol
> умал тебе перегрузка реально нужна.
ну она собственно для того и нужна, чтобы лишние функции не плодить. я вообще не представляю для чего она еще может быть нужна =)) в данном контексте )

#20
15:50, 7 фев. 2010

Nikopol
> то всё замечательно работает.
так в том то и самое интересное! что должно работать с перегрузкой, либо не должно компилироваться! на гсс же работает.....

#21
18:28, 7 фев. 2010

сигнатура виртуального метода не может быть изменена
она должна быть в точности такой, как она объявлена в базовом классе

чуваки из гцц просто кладут на возвращаемое значение (вернее смотрят наверное можно ли его прикастить static_cast'ом)

гцц много чего позволяет, например
int size = 5;
int a[size];
#22
18:49, 7 фев. 2010

Sh.Tac.
> сигнатура виртуального метода не может быть изменена
1) Перегрузка по возвращаемому значению - это допустимо в рамках языка. точнее это даже не перегрузка.
2) то, что запрещено - то вызывает ошибку компиляции.
3) гцц не кладут на возвращаемое значение! гцц какраз правильно отработал - он корректно привел указатель ObjectImp к IObject (так как между ними виртуальное наследование, то (void*)(ObjectImp*)obj != (void*)(IObject*)obj ). А вот компилятор MS какраз положил на возвращаемое значение (точнее не учел особенности виртуального наследования) и соотвественно в примере из 0ого поста мы получили неверный указатель!

> гцц много чего позволяет, например
а MSVC ругается на каждую фигню. даже шумит на a << b + c
соотвественно, еслибы мое дейсвие былобы недопустимо, компилятор обязан был завопить об ошибке.

зы.
почему так никто и не откликнулся, на просьбу проверить на других версиях VC++ =(((

#23
19:41, 7 фев. 2010

Kloun
> 1) Перегрузка по возвращаемому значению - это допустимо в рамках языка. точнее это даже не перегрузка.
недопустимо, точнее возвращаемые значения должны быть covariant с другим, и MS с этим отлично справляется и проблема не в этом
Kloun
> ну она собственно для того и нужна, чтобы лишние функции не плодить.
Советую такой подход выбросить, проектирование объектов, их разделение на бессмысленные части лишь бы не повторить одну строчку дважды - так делать нельзя
Kloun
> соотвественно, еслибы мое дейсвие былобы недопустимо, компилятор обязан был завопить об ошибке.
указатели на виртуальные таблицы при виртуальном наследовании шарятся в рантайме, компилятор не знает как изощрено ты будешь их абузить

#24
21:08, 7 фев. 2010

Kloun
если вы поменяете порядок наследования, то всё заработает, а вот почему - надо читать стандарт и думать.
очень похоже на баг компилятора.

откровенно говоря, как реализованы covariant return types в компиляторах C++ - ещё тот вопрос.
т.е. какая сущность в ответе за приведение указателя.
вызываемая виртуальная функция точно не знает, кто её вызывает, поэтому она приводить ничего не может.
вызывающий тоже не знает, какая именно реализация будет вызвана, и не подозревает о том, какого типа то, что вернулось.

#25
21:35, 7 фев. 2010

Дмитрий Ясенев
> вызываемая виртуальная функция точно не знает, кто её вызывает, поэтому она
> приводить ничего не может.
> вызывающий тоже не знает, какая именно реализация будет вызвана, и не
> подозревает о том, какого типа то, что вернулось.
ИМХО в таком случае на этапе компиляции должна создаваться промежуточная функция, в которой результат приводится, и ссылка на нее указыватся в таблицу методов для базавого класса. гцц наверно так и делает, раз у него все работает.

Дмитрий Ясенев
> если вы поменяете порядок наследования,
всмысле? наследовать базовый класс от дочернего? порядок наследования определяется архитектурой.

ashujon
> Советую такой подход выбросить, проектирование объектов, их разделение на
> бессмысленные части лишь бы не повторить одну строчку дважды - так делать
> нельзя
0й пост читал? там по коду по-моему очевидно для чего такая структура наследования. если не понятно спроси конкретней, если есть альтернативный вариант - с удовльствием выслушаю.

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

struct base { virtual base* a() = 0; }
struct derived: virtual base { virtual derived* a() = 0; }
компилятору уже на этапе генерации кода известно, что наследование виртуальное, и что сигнатуры одного и тогоже метода отличаются.
по твоей логике компилятор должен мне позволить скомпилить
struct base { virtual int a() = 0; }
struct derived: virtual base { virtual void* a() = 0; }
и якобы это будет моей ошибкой.

я лично другого мнения, компилятор должне либо компилировать корректный код, либо должен сообщать об ошибке!
яже не виню его в том, что он компилит (derived*)(void*)(base*)a; в таком случае понятно, что он ничего не может сделать с кривыми руками программиста.

#26
8:54, 8 фев. 2010

Kloun
> почему так никто и не откликнулся, на просьбу проверить на других версиях VC++ =(((
  Шестая студия не позволяет переопределять виртуальные функции с другим типом возвращаемого значения. Предположу, что 7-я, 8-я и 9-й будут работать одинаково.

#27
16:16, 8 фев. 2010

Kloun
> почему так никто и не откликнулся, на просьбу проверить на других версиях VC++
> =(((

2005-ая так же.

#28
16:45, 8 фев. 2010

Kloun
А что бы Вы, уважаемый, таки, ожидали в таком случае:

struct IObject
{
  virtual IObject* create() = 0;
};

struct IObjectModel : virtual IObject
{
  virtual IObjectModel *create() { return new IObjectModel; }
};

struct ObjectImp : virtual IObject
{
  virtual ObjectImp* create() { return new ObjectImp;  }
};

struct ObjectModelImp : IObjectModel, ObjectImp { };

Я бы, таки, ожидал, что вызовется метод IObjectModel::create в худшем случае.
А если по-православному, то ошибку компиляции с сообщением, что компилятор не смог выбрать подходящий метод.

Вообще, в данном случае, ИМО, поведение MSVC оправдано правилами вызова конструкторов при наличии виртуального наследования. А остальное в руках программиста (для правильного вызова надо привести типы).
GCC реализует дополнительную логику при сборке таблицы виртуальных ф-ций, или применяет магию dynamic_cast при вызове метода (что существенно медленней).

Таким образом, полагаю, что мы столкнулись с разной реализацией "тёмного угла" C++.

#29
16:49, 8 фев. 2010

Виртуальное наследование - зло палюбому.
Вы попробуйте IObject привести к ObjectImp без RTTI и dynamic_cast. Надеюсь, компилятор отправит вас лесом.
Если это не так, то подобных граблей на вашем пути предостаточно.

Страницы: 1 2 3 4 5 6 7 Следующая »
ПрограммированиеФорумОбщее

Тема в архиве.