Перегрузка операторов C++
От: PavelCH  
Дата: 09.08.09 15:19
Оценка:
Здраствуйте все.

Не подскажите как правильно перегрузить преобразование к типу int/unsigned? Например есть код:

class VRGB
{
public:
   // Красная компонента
   unsigned char    r;
   // Зеленая компонента
   unsigned char    g;
   // Голубая компонента
   unsigned char    b;
   // Альфа-составляющая
   unsigned char    a;
public:
   // Перегрузка при ведения к типу int
   operator int(){return *((int*)this);}
   // Конструктор для типа int
   VRGB(int Integer){ *((int*)this) = Integer; }
}

void SomeAction(int SomeValue)
{
...
}

int main()
{
   int  a;
   VRGB b;
   b = a;
   a = b;
   SomeAction(b);
}


Класс VRGB занимает 4 байта, ровно столько сколько занимает переменная типа int. Я правильно написал перегрузку? Будет ли работать код корректно если переменная b, будет хранится, например, в регистре? Или надо писать код перегрузки приведения по-другому?
Нехай щастить
перегрузка операторов
Re: Перегрузка операторов C++
От: Анатолий Широков СССР  
Дата: 09.08.09 17:02
Оценка:
Здравствуйте, PavelCH, Вы писали:

PCH>Здраствуйте все.


PCH>Не подскажите как правильно перегрузить преобразование к типу int/unsigned? Например есть код:


PCH>
PCH>class VRGB
PCH>{
PCH>public:
PCH>   // Красная компонента
PCH>   unsigned char    r;
PCH>   // Зеленая компонента
PCH>   unsigned char    g;
PCH>   // Голубая компонента
PCH>   unsigned char    b;
PCH>   // Альфа-составляющая
PCH>   unsigned char    a;
PCH>public:
PCH>   // Перегрузка при ведения к типу int
PCH>   operator int(){return *((int*)this);}
PCH>   // Конструктор для типа int
PCH>   VRGB(int Integer){ *((int*)this) = Integer; }
PCH>}

PCH>void SomeAction(int SomeValue)
PCH>{
PCH>...
PCH>}

PCH>int main()
PCH>{
PCH>   int  a;
PCH>   VRGB b;
PCH>   b = a;
PCH>   a = b;
PCH>   SomeAction(b);
PCH>}
PCH>


PCH>Класс VRGB занимает 4 байта, ровно столько сколько занимает переменная типа int. Я правильно написал перегрузку? Будет ли работать код корректно если переменная b, будет хранится, например, в регистре? Или надо писать код перегрузки приведения по-другому?


Если вы хотите закодировать цвет целочисленным значением, то надо использовать в операторе приведения явную формулу:

colour = (r << 24) + (g << 16) + (b << 8) + a;
или
colour = (a << 24) + (b << 16) + (g << 8) + r;
в зависимости от того, какой способ кодирования используется вашей графической библиотекой.
Re[2]: Перегрузка операторов C++
От: PavelCH  
Дата: 09.08.09 17:37
Оценка:
Здравствуйте, Анатолий Широков, Вы писали:

АШ>Если вы хотите закодировать цвет целочисленным значением, то надо использовать в операторе приведения явную формулу:


АШ>colour = (r << 24) + (g << 16) + (b << 8) + a;

АШ>или
АШ>colour = (a << 24) + (b << 16) + (g << 8) + r;
АШ>в зависимости от того, какой способ кодирования используется вашей графической библиотекой.

Моя задача донести компилятору, чтобы при, допустим вызове функции SomeAction, компилятор сгенерил код посылки 32 разрядного регистра/переменной в стэк, когда будет передовать параметры. По-моему в данной перегрузке он (компилятор VS2005) перед посылкой параметра в стэк сгенерит код ненужного преобразования 4 отдельных байт в 32 разрядное двойное слово, или я не прав? В графической библиотеке быстродействие критично
Нехай щастить
Re[3]: Перегрузка операторов C++
От: Erop Россия  
Дата: 09.08.09 21:01
Оценка: +1
Здравствуйте, PavelCH, Вы писали:

PCH>Моя задача донести компилятору, чтобы при, допустим вызове функции SomeAction, компилятор сгенерил код посылки 32 разрядного регистра/переменной в стэк, когда будет передовать параметры. По-моему в данной перегрузке он (компилятор VS2005) перед посылкой параметра в стэк сгенерит код ненужного преобразования 4 отдельных байт в 32 разрядное двойное слово, или я не прав? В графической библиотеке быстродействие критично


Нормальные компиляторы они того, в курсе, что в бите 8 байт и всё такое. Так что выражение вида (r<<16) | (g<<8) | (b) может оптимизировать. А вот твои художества с преобразованием невыровненных указателей нет...

Так что начать надо с простого вопроса -- что за компилятор?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Перегрузка операторов C++
От: andrey.desman  
Дата: 09.08.09 21:05
Оценка:
Здравствуйте, PavelCH, Вы писали:

Так низзя. Ты сделай наоборот — храни int:
class VRGB
{
protected:
   int rgba;
public:
   // Красная компонента
   unsigned char    getR()  {return (unsigned char)( rgba ); }
   // Зеленая компонента
   unsigned char    getG()  {return (unsigned char)( rgba >> 8 ); }
   // Голубая компонента
   unsigned char    getB()  {return (unsigned char)( rgba >> 16 ); }
   // Альфа-составляющая
   unsigned char    getA()  {return (unsigned char)( rgba >> 24 ); }
public:
   // Перегрузка при ведения к типу int
   operator int(){return rgba;}
   // Конструктор для типа int
   VRGB(int Integer): rgba(Integer) {}
}


Если есть сомнения насчет скорости доступа с помощью сдвига, то можно доступаться к байтам, что чревато проблемами с порядком байт на целевой платформе.
   unsigned char    getR()  {return 0[(unsigned char *)&rgba]; }
   unsigned char    getG()  {return 1[(unsigned char *)&rgba]; }
   unsigned char    getB()  {return 2[(unsigned char *)&rgba]; }
   unsigned char    getA()  {return 3[(unsigned char *)&rgba]; }
Re[2]: Перегрузка операторов C++
От: superman  
Дата: 10.08.09 06:51
Оценка: 1 (1)
Здравствуйте, andrey.desman, Вы писали:

AD>
AD>    0[(unsigned char *)&rgba]
AD>


У блин, а зачем такое страшное писать? скобочку экономите что ли? как-нибудь так не понятней?


((unsigned char *)&rgba)[0]
Re: Перегрузка операторов C++
От: Мишень-сан  
Дата: 10.08.09 07:30
Оценка: -1
Здравствуйте, PavelCH, Вы писали:

Не проще так?

PCH>
PCH>struct VRGB
PCH>{
PCH>public:
PCH>   union
PCH>   {
PCH>      struct
PCH>      {
PCH>         // Красная компонента
PCH>         unsigned char red;
PCH>         // Зеленая компонента
PCH>         unsigned char green;
PCH>         // Голубая компонента
PCH>         unsigned char blue;
PCH>         // Альфа-составляющая
PCH>         unsigned char alpha;
PCH>         // Цвет в виде целого
PCH>      };
PCH>      unsigned int     color;
PCH>   };
PCH>public:
PCH>   // Перегрузка при ведения к типу int
PCH>   operator int& () { return color; }
PCH>   operator const int& () const { return color; }
PCH>   // Конструктор для типа int
PCH>   VRGB(unsigned int other) { color = other; }
PCH>};

PCH>void SomeAction(int SomeValue)
PCH>{
PCH>...
PCH>}

PCH>int main()
PCH>{
PCH>   int  a;
PCH>   VRGB b;
PCH>   b = a;
PCH>   a = b;
PCH>   SomeAction(b);
PCH>}
PCH>


В результате все четыре компоненты автоматом пакуются в целое.
Re[4]: Перегрузка операторов C++
От: PavelCH  
Дата: 10.08.09 07:49
Оценка:
Здравствуйте, Erop, Вы писали:

E>Нормальные компиляторы они того, в курсе, что в бите 8 байт и всё такое. Так что выражение вида (r<<16) | (g<<8) | (b) может оптимизировать. А вот твои художества с преобразованием невыровненных указателей нет...


Посмотрел я во что он превращает мои художества Тестил на следующем коде (долго возился с тем, чтобы он не сокращал все до присваивания результата SomeValue одним оператором mov [SomeValue], <результат>, наконец подобрал код ):

static int SomeValue;
static VRGB c2(10,10,10);

int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
      SomeValue = c2;
}


Вот что создал компилятор:

0040A705 mov eax,dword ptr ds:[00435EF8h]
0040A70A movzx ecx,al
0040A70D shl ecx,8
0040A710 movzx edx,ah
0040A713 movzx eax,byte ptr ds:[435EFAh]
0040A71A add ecx,edx
0040A71C movzx edx,byte ptr ds:[435EFBh]
0040A723 sub esp,0F0h
0040A729 shl ecx,8
0040A72C push ebx
0040A72D add ecx,eax
0040A72F push edi
0040A730 shl ecx,8
...
0040A738 add ecx,edx
...
0040A73F mov dword ptr [SomeValue], ecx

То есть делаю вывод, что компилятор не понял всю глубину моей мысли. Или я че-то не правильно объяснил ему

E>Так что начать надо с простого вопроса -- что за компилятор?

Компилятор Visual Studio 2005. Пишу под винду.
Нехай щастить
Re[2]: Перегрузка операторов C++
От: PavelCH  
Дата: 10.08.09 07:57
Оценка:
Здравствуйте, Мишень-сан, Вы писали:

МС>Не проще так?


PCH>>
PCH>>struct VRGB
PCH>>{
PCH>>public:
PCH>>   union
PCH>>   {
PCH>>      struct
PCH>>      {
PCH>>         // Красная компонента
PCH>>         unsigned char red;
PCH>>         // Зеленая компонента
PCH>>         unsigned char green;
PCH>>         // Голубая компонента
PCH>>         unsigned char blue;
PCH>>         // Альфа-составляющая
PCH>>         unsigned char alpha;
PCH>>         // Цвет в виде целого
PCH>>      };
PCH>>      unsigned int     color;
PCH>>   };
PCH>>public:
PCH>>   // Перегрузка при ведения к типу int
PCH>>   operator int& () { return color; }
PCH>>   operator const int& () const { return color; }
PCH>>   // Конструктор для типа int
PCH>>   VRGB(unsigned int other) { color = other; }
PCH>>};

PCH>>void SomeAction(int SomeValue)
PCH>>{
PCH>>...
PCH>>}

PCH>>int main()
PCH>>{
PCH>>   int  a;
PCH>>   VRGB b;
PCH>>   b = a;
PCH>>   a = b;
PCH>>   SomeAction(b);
PCH>>}
PCH>>


МС>В результате все четыре компоненты автоматом пакуются в целое.


Почти так было раньше Раньше у меня был просто union и struct без класса (то есть всегда писал i = rgb.l. Я захотел повзрослому через классы, через перегрузку. Но до такого варианта, который вы предложили, конечно не додумался.

Я так понял вопрос решен. Всем спасибо, теперь буду знать методику

В догонку вопрос к автору, а обязательно ли ставить амперсанд в конструкции:

operator int& ()


На что влияет если без него?
Нехай щастить
Re[3]: Перегрузка операторов C++
От: Мишень-сан  
Дата: 10.08.09 08:58
Оценка:
Здравствуйте, PavelCH, Вы писали:

PCH>В догонку вопрос к автору, а обязательно ли ставить амперсанд в конструкции:


PCH>
PCH>operator int& ()
PCH>


PCH>На что влияет если без него?


Не обязательно. Просто это приводит к возврату не копии значения, а ссылки на него.
Т.е. потом можно писать
...
VRGB rgb;
(int)rgb = 12345;
...

Как результат, если некая функция принимает ссылку на целое для изменений в своих потрохах, ей можно будет внаглую передавать Ваш тип, он будет автоматом преобразован к ссылке на целое, и функция его молча поменяет.
Хотя, вот подумал...
Скорее это будет небезопасно. Лучше явно описывать свои намерения.
Если надо работать с типом как с обычным int, операторы перегрузить придётся всё равно. Иначе в каждом присваивании придётся писать явное приведение.

Если не полностью в курсе, что есть ссылки и чем они отличаются от указателей, советую почитать соотв. раздел Страуструпа "С++".
Если же коротко, ссылки в отличие от указателей:
1. Инициализируются при создании, в дальнейшем переопределению не подлежат.
2. Ведут себя как сам объект или значение, на который ссылаются.
3. Могут быть инициализированы только lvalue (грубо — переменными).
Активно применяются в перегрузке операторов; также неплохо применять, когда надо передать в функцию объект или структуру большого объёма, копировать которую нежелательно.
Re[2]: Перегрузка операторов C++
От: andrey.desman  
Дата: 10.08.09 09:53
Оценка:
Здравствуйте, Мишень-сан, Вы писали:

МС>Не проще так?

МС>В результате все четыре компоненты автоматом пакуются в целое.

Так тоже нельзя — UB, да и в добавок все равно проблемы с LE/BE. Но в большинстве случаев конечно сойдет.
Re[3]: Перегрузка операторов C++
От: andrey.desman  
Дата: 10.08.09 09:56
Оценка:
Здравствуйте, superman, Вы писали:

AD>>
AD>>    0[(unsigned char *)&rgba]
AD>>


S>У блин, а зачем такое страшное писать? скобочку экономите что ли? как-нибудь так не понятней?


S>
S>((unsigned char *)&rgba)[0]
S>


Это не важно — у каждого свой взгляд на "красоту". Но мне, лучше уж так:
*((unsigned char *)&rgba + 0)
Re[4]: Перегрузка операторов C++
От: Programador  
Дата: 10.08.09 10:16
Оценка:
Здравствуйте, andrey.desman, Вы писали:

AD>Это не важно — у каждого свой взгляд на "красоту". Но мне, лучше уж так:

AD>
AD>*((unsigned char *)&rgba + 0)
AD>



0[(unsigned char(&)[4])rgba];
Re[4]: Перегрузка операторов C++
От: Programador  
Дата: 10.08.09 10:26
Оценка:
Здравствуйте, Erop, Вы писали:

E>Нормальные компиляторы они того, в курсе, что в бите 8 байт и всё такое. Так что выражение вида (r<<16) | (g<<8) | (b) может оптимизировать. А вот твои художества с преобразованием невыровненных указателей нет...


Это врядли. Единственное что может быть проверка указателя на 0, поскольку 0всегда 0, даже при смене офсета. Но не в этом случае и у какогото очень тупого компилятора. Можно к ссылке приводить. Ссылки void& не бывает, поэтому ссылку ни проверять ноль, ни промежуточно использовать { (Y&)(void&)X; } не нужно.
Re[5]: Перегрузка операторов C++
От: Erop Россия  
Дата: 10.08.09 10:27
Оценка:
Здравствуйте, Programador, Вы писали:

E>>А вот твои художества с преобразованием невыровненных указателей нет...


P>Это врядли.


Ещё будет чтение невыровненного int...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: Перегрузка операторов C++
От: Programador  
Дата: 10.08.09 10:49
Оценка:
Здравствуйте, Erop, Вы писали:

E>Ещё будет чтение невыровненного int...

rgb всеравно от байт ордер зависит, так что платформонезависимой не получится
Re[3]: Перегрузка операторов C++
От: Мишень-сан  
Дата: 10.08.09 10:52
Оценка:
Здравствуйте, andrey.desman, Вы писали:

AD>Здравствуйте, Мишень-сан, Вы писали:


МС>>Не проще так?

МС>>В результате все четыре компоненты автоматом пакуются в целое.

AD>Так тоже нельзя — UB, да и в добавок все равно проблемы с LE/BE. Но в большинстве случаев конечно сойдет.


Гм, а где там UB, не подскажете? Честно, не в курсе просто.
Re[5]: Перегрузка операторов C++
От: Programador  
Дата: 10.08.09 11:12
Оценка:
AD>>
AD>>*((unsigned char *)&rgba + 0)
AD>>


Что-то я пропустил. Это теперь допустимый код без (void*) ? Жесткое послабление на фоне остальных строгостей
Re[4]: Перегрузка операторов C++
От: Юрий Жмеренецкий ICQ 380412032
Дата: 10.08.09 11:27
Оценка:
Здравствуйте, Мишень-сан, Вы писали:

МС>Здравствуйте, PavelCH, Вы писали:


PCH>>В догонку вопрос к автору, а обязательно ли ставить амперсанд в конструкции:


PCH>>
PCH>>operator int& ()
PCH>>


PCH>>На что влияет если без него?


МС>Не обязательно. Просто это приводит к возврату не копии значения, а ссылки на него.

МС>Т.е. потом можно писать
МС>
МС>...
МС>VRGB rgb;
МС>(int)rgb = 12345;
МС>...
МС>

МС>Как результат, если некая функция принимает ссылку на целое для изменений в своих потрохах, ей можно будет внаглую передавать Ваш тип, он будет автоматом преобразован к ссылке на целое, и функция его молча поменяет.

Вменяемый компилятор не должен это компилировать, т.к. левым операндом оператора присваивания должно быть modifiable lvalue.
Re[5]: Перегрузка операторов C++
От: Мишень-сан  
Дата: 10.08.09 11:41
Оценка:
Здравствуйте, Юрий Жмеренецкий, Вы писали:

ЮЖ>Вменяемый компилятор не должен это компилировать, т.к. левым операндом оператора присваивания должно быть modifiable lvalue.


Ну это был VC8.0
Хотя конструкция дурацкая, согласен.
Не знаю что меня вообще дёрнуло писать приведение к ссылке.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.