Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Visual C++/MFC/WTL > Функция, возвращающая любой тип данных?


Автор: maq 19.2.2006, 19:05
У меня такая проблема:

Нужно создать функцию, которая в зависимости от обработки (в теле самой функции), будет возвращать различные типы данных, например:

Код

switch(Condition)
{
case 1:
      HBITMAP hBitmap;
      ....
      return hBitmap;
      break;
case 2:
      HICON hIcon;
      ....
      return hIcon;
      break;
}

Кто-нибудь может помочь?

Автор: Mayk 19.2.2006, 19:15
Хмм. При сильном желании HBITMAP и HICON можно откастить в HANDLE.
Только надо ли оно?

Ну еще можно использовать union'ы, или модный ныне http://boost.org/doc/html/any.html


ps. не стоит писать break после return'а. такой break никогда ничего не прервёт.

Автор: kanSC 20.2.2006, 00:27
Пусть функция возвращает void*. А после вызова приводи возвращаемое значение к нужному тебе типу.

Автор: DeadSoul 20.2.2006, 01:18
Цитата(kanSC @ 20.2.2006, 00:27 Найти цитируемый пост)
Пусть функция возвращает void*. А после вызова приводи возвращаемое значение к нужному тебе типу

Оторвать руки за такие советы. А как определить к какому типу приводить?

Можно использовать:
1. variant
2. boost::variant(с первым пунктом имеет мало общего)

А в принципе тут скорее всего ошибка проектирования. Исходную задачу обнародуй

Автор: chipset 20.2.2006, 01:38
Отставить отрывание рук smile

Цитата(Mayk @ 19.2.2006, 09:15 Найти цитируемый пост)
Хмм. При сильном желании HBITMAP и HICON можно  откастить в HANDLE.

Не нужно большого желания. HBITMAP и HICON это typedef'ы HANDLE.
Добавлено @ 01:40
Если-же нужна реализация фабрики обьектов для других типов то:
1. Создаем базовой обьект с виртуальной функцией.
2. В switch'e наполняем вирт. функцию содержимым.
3. Возвращаем полиформно измененный обьект.

Автор: maq 20.2.2006, 20:03
DeadSoul, chipset, а если по-подробнее, пожалуйста.
И если можно с примером...

Пробовал с VARIANT:
Код

VARIANT AAA(void);

Код

VARIANT RSplash::AAA(void)
{
    int B = 1;
switch(B)
{
case 1:
      HBITMAP hBitmap;
      return hBitmap;
case 2:
      HICON hIcon;
      return hIcon;
}
    return VARIANT();
}


ошибка:
Error 1 error C2664: 'tagVARIANT::tagVARIANT(const tagVARIANT &)' : cannot convert parameter 1 from 'HBITMAP' to 'const tagVARIANT &' c:\.....\rsplash.cpp 251

Код

variant AA(void);


Код

variant RSplash::AA(void)
{
    return variant();
}


теперь уже уйма ошибок! (кажется ошибка синтаксиса)

Автор: Mayk 20.2.2006, 20:22
Цитата(maq @ 21.2.2006, 00:03 Найти цитируемый пост)
если по-подробнее, пожалуйста.


Код

HANDLE func(int Condition)
{
    switch(Condition)
    {
        case 1:
             HBITMAP hBitmap;
             ....
            return (HANDLE)hBitmap;
           break;
       case 2:
          HICON hIcon;
           ....
         return (HANDLE)hIcon;
      break;
}

Автор: DeadSoul 20.2.2006, 23:32
Цитата(maq @ 20.2.2006, 20:03 Найти цитируемый пост)
DeadSoul, chipset, а если по-подробнее, пожалуйста.

Фигню сморозил. Как-то забыл о том, что это все typedef-ы для void*

maq, я бы подумал над разнесением этой функции на несколько

Автор: chipset 20.2.2006, 23:51
Цитата(DeadSoul @ 20.2.2006, 13:32 Найти цитируемый пост)
maq, я бы подумал над разнесением этой функции на несколько

Зачем?

Автор: DeadSoul 21.2.2006, 00:44
chipset, а как с ней извне работать? Ты не знаешь, что там HICON,HBITMAP(а Api разные)
А внутри функции все равно switch\что-то shitch-е подобное

Автор: bel_nikita 21.2.2006, 00:53
Ну вот, такое извращение:
Код

typedef struct __stRetValue{
  enum eType{ RET_UNKNOWN, RET_HBITMAP, RET_HICON };
  union{
    HBITMAP hBitmap;
    HICON hIcon;
  };
  eType Type;
} RETVALUE;

RETVALUE RSplash::AAA(void)
{
RETVALUE Ret;
    int B = 1;
switch(B)
{
case 1:
      HBITMAP hBitmap;
      Ret.Type = RETVALUE::RET_HBITMAP;
      Ret.hBitmap = hBitmap;
break;
case 2:
      HICON hIcon;
      Ret.Type = RETVALUE::RET_HICON;
      Ret.hIcon = hIcon;
break;
}
    return Ret;
}

...

RETVALUE Value = RSplash::AAA();
switch (Value.Type)
{
case RETVALUE::RET_HBITMAP:
      HBITMAP hBitmap = Value.hBitmap;
break;
case RETVALUE::RET_HICON:
      HICON hIcon = Ret.hIcon;
break;
};


Автор: DeadSoul 21.2.2006, 01:47
bel_nikita, RETVALUE -> std::pair<...> smile

Автор: maq 21.2.2006, 19:50
Задача такая вот:

Код

HANDLE LoadFromExtRes(CString strFileName, int intResId, int intResType);


Код

HANDLE RSplash::LoadFromExtRes(CString strFileName, int intResId, int intResType)
{
    HMODULE h_resDll = LoadLibraryEx(strFileName, NULL, LOAD_LIBRARY_AS_DATAFILE);
    if(h_resDll != NULL)
    {
        switch(intResType)
        {
        case DST_BITMAP:
            HBITMAP h_bitmap = LoadBitmap(h_resDll, MAKEINTRESOURCE(intResId));
                        //FreeLibrary(h_resDll);
            return h_bitmap;
        }
    }
}


Код

m_static_logo.SetBitmap(LoadFromExtRes(str_temp, 1, DST_BITMAP));


Error 1 error C2664: 'CStatic::SetBitmap' : cannot convert parameter 1 from 'HANDLE' to 'HBITMAP'

Автор: Earnest 21.2.2006, 20:07
Можно применить насилие (HBITMAP)LoadFromRes(...)
Однако с точки зрения объектного программирования, это не очень хорошо, лучше бы как-то так:
Код

class СResourceLoader
{
public:
   СResourseLoader(const CString& strFile)
  {
     m_hRes = LoadLibraryEx(strFile, NULL, LOAD_LIBRARY_AS_DATAFILE);
  }

   bool InitBitmap(CBitmap& bmp,UINT nResID) const
  {
    if (m_hRes==0) return false;

     HBITMAP hBitmap = LoadBitmap(m_hRes, MAKEINTRESOURCE(nResId));
     if (hBitmap)   { bmp.SetBitmap(hBitmap); return true; }
     else return false;
 }
private:
   HMODULE m_hRes; 
};

Использование:
Код

   CBitmap bmp;
   CResourseLoader(strName).InitBitmap(bmp,nBmpID);

Т.е. вместо одной утилитной функции используем один утилитный класс.
Добавлено @ 20:08
Да, забыла, в деструкторе библиотеку нужно выгрузить.

Автор: maq 22.2.2006, 00:28
Earnest, мне нужна именно функция

Код

HANDLE LoadFromExtRes(CString strFileName, int intResId, int intResType);

которая в зависимости от задаваемого параметра intResType (DST_BITMAP или напр. DST_ICON и т.д) возвращала бы HBITMAP или HICON.

Вместо твоего варианта я бы лучше разделил функцию LoadFromExtRes на LoadBitmapFromExtRes и LoadIconFromExtRes, которые возвращали бы HBITMAP и HICON.
Мне нужно просто объединить эти функции.

Но вот как?

Автор: bel_nikita 22.2.2006, 01:50
Цитата(maq @ 21.2.2006, 23:28)
Вместо твоего варианта я бы лучше разделил функцию LoadFromExtRes на LoadBitmapFromExtRes и LoadIconFromExtRes, которые возвращали бы HBITMAP и HICON.
Мне нужно просто объединить эти функции.

Ничего не нужно объединять. Каждая функция должна выполнять минимум. И оператор if...else... еще никто не не отменял

Автор: maq 22.2.2006, 10:11
bel_nikita,
нужна ОДНА-ЕДИНСТВЕННАЯ функция.

Создать функции
HBITMAP LloadBitmapFromExtRes
HICON LoadIconFromExtRes
- нет проблем!

Мне же нужна одна функция LoadFromExtRes, которая бы возвращала либо HBITMAP, либо HICON (в зависимости от
Цитата
if...else...
в теле функции LoadFromExtRes!

Автор: maq 22.2.2006, 16:59
Цитата
Каждая функция должна выполнять минимум

Почему?

Автор: Earnest 22.2.2006, 21:14
Цитата(maq @ 22.2.2006, 10:11 Найти цитируемый пост)
нужна ОДНА-ЕДИНСТВЕННАЯ функция.

Почему?
Но если действительно нужна именно функция, и именно одна - тогда возвращай HANDLE и используй преобразование типа при использовании. Другого выхода нет. Если ничего не перепутаешь (т.е. не попытаешься использовать HICON вместо HBITMAP), все должно работать.

Автор: chipset 22.2.2006, 21:24
ИМХО, стоит сделать оболочку ImageProcessor с виртуальной функцией ProcessImage и в LoadBitmapFromExt присваивать классу в ран-тайме либо обьект HIconImageProcessor либо HBitmapImageProcessor. Другого красивого метода я не вижу.

Автор: maq 23.2.2006, 13:26
Цитата
тогда возвращай HANDLE и используй преобразование типа при использовании

Earnest, ты это имеешь ввиду - заменить
Код
m_static_logo.SetBitmap(LoadFromExtRes(str_temp, 1, DST_BITMAP));

на
Код
m_static_logo.SetBitmap((HBITMAP)LoadFromExtRes(str_temp, 1, DST_BITMAP));

Я правильно понял?

P.S.
Цитата
Можно применить насилие (HBITMAP)LoadFromRes(...)
Однако с точки зрения объектного программирования, это не очень хорошо

Просто для интереса - а почему "не очень хорошо"?

Автор: Earnest 23.2.2006, 18:52
Да, ты понял правильно. Только не худо бы проверить, что возвращенный хандл != 0.

Нехорошо, потому что небезопасно: после выхода из LoadFromExtRes, по хандлу уже никак нельзя установить, что это - иконка или битмап. Т.е. от того, с какой константой вызвали LoadFrom... зависит, что будет делаться дальше. Лучше бы такие действия объединить намертво...
Не могу понять, чем тебе так мила единая функция?

Автор: Coocky 23.2.2006, 19:14
Долго наблюдал. smile
Снимаю рубаху, кидаюсь в рукопашную smile
Цитата(chipset @ 22.2.2006, 21:24 Найти цитируемый пост)
ИМХО, стоит сделать оболочку ImageProcessor с виртуальной функцией ProcessImage и в LoadBitmapFromExt присваивать классу в ран-тайме либо обьект HIconImageProcessor либо HBitmapImageProcessor. Другого красивого метода я не вижу.

Сильно заООПепил smile Наследие Qt.
На самом деле-решений-множество smile Тут уже по вкусу..Как по мне. так кроме "красоты", важна скорость написания и надежность кода.
Вот у меня вопрос к автору-толкнуть все в одну функцию-это чисто из любопытства или жизненое кредо? smile

Автор: maq 23.2.2006, 22:44
Цитата
Только не худо бы проверить, что возвращенный хандл != 0

Все отлично работает.

Цитата
Нехорошо, потому что небезопасно: после выхода из LoadFromExtRes, по хандлу уже никак нельзя установить, что это - иконка или битмап.

Предусмотрено уже (например):
Код
m_static_logo1.SetBitmap((HBITMAP)LoadFromExtRes(str_temp, 1, DST_BITMAP));
m_static_logo2.SetIcon((HICON)LoadFromExtRes(str_temp, 1, DST_ICON));


Цитата
Вот у меня вопрос к автору-толкнуть все в одну функцию-это чисто из любопытства или жизненое кредо?

Цитата
Не могу понять, чем тебе так мила единая функция?

Люблю простоту написания кода. А всю рутинную работу бросить в отдельную функцию. (наверное привычка от VB)
smile

Спасибо за помощь!

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)