Здравствуйте, ChainEG, Вы писали:
CEG>Способ 1, на мой взгляд, интуимтивно понятнее. CEG>Его недостаток — требуется следить, куда кастить каждое значение, и не ошибиться при этом. CEG>Если названия типов TypeA, TypeB ... имеют разную длину, то код неаккуратно выглядит.
CEG>Способ 2 интуимтивно менее понятен, но, как мне кажется лучше читаем, так как четко видна основная цель выпажения: A=Get("A"). CEG>Не нужно следить за типами: все значения кастятся в один ти тот же тип. CEG>И оформление кода получается более аккуратным
CEG>И все же, какой способ предпочтительнее?
На самом деле, при использовании GetProcAddress очень утомительно выписывать типы,
// прототип
// int __stdcall hello(const char* from, const char* to);
// ужас-ужас-ужасint (__stdcall *fun)(const char*, const char*) = (int (__stdcall*)(const char*,const char*)) GetProcAddress("hello");
fun = (int (__stdcall*)(const char*,const char*)) GetProcAddress("goodbye");
// просто ужасtypedef int (__stdcall *GREETING)(const char*, const char*);
GREETING fun = (GREETING) GetProcAddress("hello");
fun = (GREETING) GetProcAddress("goodbye");
и хочется иметь какой-то вот такой
// не заводим ненужных typedef'овint (__stdcall* fun)(const char*, const char*) = (getproc_cast) GetProcAddress("hello");
fun = (getproc_cast) GetProcAddress("goodbye");
Это несложно:
struct getproc_cast
{
FARPROC m_ptr; // результат GetProcAddress - тип, двоично совместимый с void(*)() и - особенности Windows - void*
getproc_cast(FARPROC ptr) : m_ptr(ptr) {}
template<class Ptr> operator Ptr() const { return (Ptr) m_ptr; }
};
Подобным способом можно расправиться и с другими вариантными типами (void* | void(*)() — это самые примитивные вариантные типы )
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re: Если функция возвращает значения различных типов ...
Здравствуйте, ChainEG, Вы писали:
CEG>Нужно инициализировать переменные различных типов CEG>
CEG>TypeA A;
CEG>// Способ 1
CEG>A=(TypeA)Get("A");
CEG>// Способ 2
CEG>(Type&)A=Get("A");
CEG>
Во втором случае наблюдается очень прикольное природное явление.
1) static_cast
1.1) если TypeA унаследован от Type, выполняется up-cast (обращение к базовому подобъекту), и происходит частичное присваивание — срезка наоборот
1.2) если Type унаследован от TypeA, выполняется down-cast, причём
1.2.1) если Type двоично совместим с TypeA, происходит обычное присваивание (как в 2.1)
1.2.2) если нет — т.е. sizeof(Type)!=sizeof(TypeA), то, аналогично (2.4), мы запиливаем память вокруг объекта-приёмника (причём можем расстрелять и хвост, и голову! при ненулевом смещении базы)
2) reinterpret_cast
2.1) если типы двоично совместимы (int и long на IA32, например; или две структуры с совпадающим лэяутом), происходит обычное присваивание
2.2) если совместимы условно (int и unsigned int) — поведение платформенно-зависимо; обычно ничего трагичного в этом нет
2.3) если имеют одинаковый размер, но несовместимы (long и float) — получаем мусор и, по большому счёту, неопределённое поведение; особенно, если это не POD-типы
2.4) если разный размер — то вдобавок запиливаем память
Отсюда мораль: этот способ ошибкоопасный, очень ограниченно применимый и вдобавок платформенно-зависимый.
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re: Если функция возвращает значения различных типов ...
Есть функция, которая может возвращать значения различных типов.
Type Get(const char *sz);
Нужно инициализировать переменные различных типов
TypeA A;
TypeB B;
TypeC C;
Обычно, я делал так:
// Способ 1
A=(TypeA)Get("A");
B=(TypeB)Get("B");
C=(TypeC)Get("C");
Но вот, в чужом коде увидел такой прием:
// Способ 2
(Type&)A=Get("A");
(Type&)B=Get("B");
(Type&)C=Get("C");
Какой способ лучше?
Способ 1, на мой взгляд, интуимтивно понятнее.
Его недостаток — требуется следить, куда кастить каждое значение, и не ошибиться при этом.
Если названия типов TypeA, TypeB ... имеют разную длину, то код неаккуратно выглядит.
Способ 2 интуимтивно менее понятен, но, как мне кажется лучше читаем, так как четко видна основная цель выпажения: A=Get("A").
Не нужно следить за типами: все значения кастятся в один ти тот же тип.
И оформление кода получается более аккуратным
И все же, какой способ предпочтительнее?
Re: Если функция возвращает значения различных типов ...
Здравствуйте, jazzer, Вы писали:
CEG>>Есть функция, которая может возвращать значения различных типов.
В смысле, она возвращает значение некоего общего типа Type, которое предлагается откастить в нужный тип: TypeA, TypeB ...
Пример такой функции: GetProcAddress()
Re: Если функция возвращает значения различных типов ...
CEG>Есть функция, которая может возвращать значения различных типов. CEG>
CEG>Type Get(const char *sz);
CEG>
CEG>Нужно инициализировать переменные различных типов CEG>
CEG>TypeA A;
CEG>TypeB B;
CEG>TypeC C;
CEG>
CEG>Обычно, я делал так: CEG>
CEG>// Способ 1
CEG>A=(TypeA)Get("A");
CEG>B=(TypeB)Get("B");
CEG>C=(TypeC)Get("C");
CEG>
CEG>Но вот, в чужом коде увидел такой прием: CEG>
CEG>// Способ 2
CEG>(Type&)A=Get("A");
CEG>(Type&)B=Get("B");
CEG>(Type&)C=Get("C");
CEG>
CEG>Какой способ лучше? CEG>Способ 1, на мой взгляд, интуимтивно понятнее. CEG>Его недостаток — требуется следить, куда кастить каждое значение, и не ошибиться при этом. CEG>Если названия типов TypeA, TypeB ... имеют разную длину, то код неаккуратно выглядит.
CEG>Способ 2 интуимтивно менее понятен, но, как мне кажется лучше читаем, так как четко видна основная цель выпажения: A=Get("A"). CEG>Не нужно следить за типами: все значения кастятся в один ти тот же тип. CEG>И оформление кода получается более аккуратным
CEG>И все же, какой способ предпочтительнее?