Страница 2 из 2

Добавлено: 21 мар 2007, 22:50
ajkj3em
Azazello писал(а):
aissp писал(а):Мне кажется не очень хороший стиль, когда по сути есть два различных места хранения инфо о типе. ДА и не верю я в корректную работу тайпАйдИ :) (ето основная причина)
Согласен - некрасиво дублировать. Просто, RTTI всё равно нужно для dynamic_cast и virtual destructor clean-up
для последнего rtti не нужен. виртуальный деструктор окучиваетcя
стандартной таблицей виртуальных методов класса
aissp, то есть, Вы dynamic_cast совсем не пользуете (просто интересно, как люди пишут ;))
я не аиссп, но как-то грех не влезть :) использование dynamic_cast
в коде практически гарантировано означает наличие кривого дизайна.
практически любую задачу решенную с помошью upcast'инга можно
всегда переписать без такового. к тому же на практике dynamic_cast
компилируетcя в достаточно тяжелый код, что тоже не есть хорошо

Добавлено: 21 мар 2007, 22:53
ajkj3em
aissp писал(а):А с динамиком - мне кажется единственное место где он применяется ето когда условия изменились настолько что надо передизайнить а на ето нету времени, либо код совсем чужой и никакими адаптерами не спасешься - действия должны происходить внутри кода.
O!
Красивый пример никак в голову не лезет. сорри
NalejTovarish() ? не помню что за пример, но он точно красивый :)

Re: С vs С++

Добавлено: 22 мар 2007, 13:02
i_van
ajkj3em писал(а):
i_van писал(а):Я так и выкрутился. Однако при этом use_int() теряет строгое типизирование и может быть вызвана не с первоначально требуемым аргументом int* . В этом-то я и вижу кривизну, которой хотелось бы избежать.
строгое типизирование теряетcя при первом downcast'е в void.

в оригинальном коде ничего не мешает вызвать greeting(use_int, &f_age),
так шта кривизна там присутcтвует и без С++
Речь идет несколько о другом: о замене use_int(int* ) на use_int(void* ). Лично у меня use_int(int* ) вызывается из многих мест и потому хотелось бы ее сохранить - это первое.

Однако основная кривизна после замены use_int(int* ) на use_int(void* ) начинается дальше.

Имея только прототип, и не зная про кастинг внутри функции, другие парни начинают вызывать use_int(void* ), но они понятия не имеют какой пойнтер должен быть подставлен и прокастинген до (void *). Они могут вызвать use_int((void*) fff), где fff было объявлена как float. Помним, что это use_int только пример, название которого подсказывает, что надо использовать int*. А в жизни название функции может не отражать связи с аргументом.

Вот как криво-то вышло :)

Добавлено: 22 мар 2007, 13:11
aissp
Пользуй темплайт - при попутке использования с разными типами получишь ошибку компиляции.

Добавлено: 22 мар 2007, 13:56
i_van
aissp писал(а):Пользуй темплайт - при попутке использования с разными типами получишь ошибку компиляции.
Template есть быть карашо... Это была и у меня версия 2. Однако тоже не без кривизны.

Допустим я объявил функцию greeting() через template. После компиляции я получу в коде столько версий greeting(), сколько типов использовал. Код раздулся...

A в С была версия только одна версия функции, и было все компактненько.

Вот кривенько-то опять и вышло :).

Похоже не может С++ сделать это лучше чем С, во всяком случае я пока лучшей версии не нашел...

Добавлено: 22 мар 2007, 15:44
Azazello
i_van писал(а):Похоже не может С++ сделать это лучше чем С, во всяком случае я пока лучшей версии не нашел...
i_van, если речь идёт о том, чтоб работало с минимальными изменениями, то как насчёт:

Код: Выделить всё

...
typedef void( * LET_MY_FUNCTION_PASS )( void * );
void greeting( LET_MY_FUNCTION_PASS, void * );

int main( void )
 {
  ...
  p = &i_age;
  greeting( ( LET_MY_FUNCTION_PASS ) use_int, p ); //first call
  
  p = &f_age;
   greeting( ( LET_MY_FUNCTION_PASS ) use_float, p ); //second call
  ...
 }
...
Кстати, я подозреваю, что дело не в C или С++, а в том, позволяет ли компилятор неявные преобразования типа. Мне кажется, что С-компиляторы тоже должны ругаться на изначальный вариант:

Cannot convert 'void(*)(int*) to 'void(*)(void*)'

Разве нет?

Добавлено: 22 мар 2007, 15:47
aissp
И ето не так, ты можешь специализировать стока темплатов скока надо а в остальные бросить ошибку for example:


Код: Выделить всё

template <typename T> void func( void (*fp)(T*), T* q) { 
assert(false);
}

template <> void func( (*fp)(int*)... { }

вот код и не раздувается уже

понимаю причины неделанбя етого но вот тебе ощибка на стадии компиляции

Код: Выделить всё

#define MYASSERT(boolexp) {char myarray[(boolexp) ? 1 : 0]; }

и используешь в общем темплате вместо ассерта

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

тогда в темплате мы вызываем greetings as is а перед ним устраиваем проверку типов. соотвественно твой код разбухает ровно на код необходимый для проверки типа. да и тут можно что нибудь придумать

Добавлено: 22 мар 2007, 18:14
Azazello
aissp и ajkj3em.
Во-первых, спасибо за поддержание дискуссии ;).
Во-вторых, честно говоря, я dynamic_cast напрямую и сам никогда не использую - некрасиво. Хотел узнать, что умные люди по этому поводу думают ;). В принципе, по-моему, virtual functions и templates достаточно, чтобы такого использования избежать (если не считать проблемы адаптации чужого кода, с чем лично я, честно говоря, сталкиваюсь не так часто)... То есть, философия такая: downcasting и cross-casting - это плохой стиль, и может быть использован только в исключительных (см. выше) случаях, верно?
В-третьих, насчёт virtual destructor clean-up я был не прав - это был какой-то рудиментарное руководство к компилятору в памяти всплыло... Имелось ввиду, что многие имплементации используют RTTI с exception handling в catch.

Добавлено: 22 мар 2007, 19:57
Leo Gan
На С# все проще делается, с помощью delegate. Все типизировано.

Добавлено: 22 мар 2007, 20:58
aissp
дык на перле еше проще там и типизовать ен нада.

но проше всего(не устану повторять) делается на петровиче.

гришь ему - doit и он все делает 8)

Добавлено: 22 мар 2007, 21:12
Leo Gan
aissp писал(а):дык на перле еше проще там и типизовать ен нада.

но проше всего(не устану повторять) делается на петровиче.

гришь ему - doit и он все делает 8)
Ага, Ruby on Rails REST :lol: