Russian Qt Forum

Программирование => С/C++ => Тема начата: Igors от Июня 26, 2010, 12:14



Название: Наследование от простой структуры
Отправлено: Igors от Июня 26, 2010, 12:14
Добрый день

Есть простая структура в стиле С

Код
C++ (Qt)
struct RGB {
float r, g, b;
};
Проект содержит много файлов на чистом С, делать RGB классом С++ не с руки. Но для новых файлов (на С++) мне конечно не хочется писать действия 3 раза (для r, g, b). Поэтому я унаследовался

Код
C++ (Qt)
struct RGB2 : public RGB {
// конструктора нет (по техническим причинам нежелателен)
...
RGB2 & operator = ( float f )  { r = g = b = f; return *this; }
...
// еще много операторов для удобства
};
 
Это работает нормально, но

Код
C++ (Qt)
RGB test1 = { 0.0f };    // так можно
RGB2 test2 = { 0.0f };   // так нельзя
 
RGB2 test3;
test3 = 0.0f;              // так можно
 
RGB2 test4 = 0.0f;       // а так нельзя
 
Можно ли как-то устранить эти мелкие неудобства для RGB2 ?

Спасибо


Название: Re: Наследование от простой структуры
Отправлено: SABROG от Июня 26, 2010, 14:25
Ты пытаешься скрестить POD тип с классом C++. Интерфейс класса написать можно, но к этому интерфейсу придется приводить тип, чтобы воспользоваться его методами, но как я понял приведение типов тебя не устраивает по какой-то причине.

Кстати класс QRgb более оптимизирован для работы с цветами представленными действительными типом. В нем используется трюк, который использовали на процессорах где отсутствуют операции с действительными числами (приставках, мобильниках) - fixed point арифметика. float число представляется целочисленным. Помимо того, что код становится более переносимым на другие архитектуры, так он еще и в разы становится быстрее, так как операции с такими целочисленными типами быстрее.


Название: Re: Наследование от простой структуры
Отправлено: Igors от Июня 26, 2010, 15:24
Интерфейс класса написать можно, но к этому интерфейсу придется приводить тип, чтобы воспользоваться его методами, но как я понял приведение типов тебя не устраивает по какой-то причине.
Меня это приведение вполне устраивает, я спрашиваю как поудобнее сделать присваивание/инициализацию

Кстати класс QRgb более оптимизирован для работы с цветами представленными действительными типом. В нем используется трюк, который использовали на процессорах где отсутствуют операции с действительными числами (приставках, мобильниках) - fixed point арифметика. float число представляется целочисленным. Помимо того, что код становится более переносимым на другие архитектуры, так он еще и в разы становится быстрее, так как операции с такими целочисленными типами быстрее.
Процессор PowerPC (big endian) не выпускается уже лет 5. Но он уже был RISC, значит все команды выполняются за 1 такт, значит умножение (и др. операции) с float происходят с той же скоростью что и с (long)int. Про новые процессоры Intel деталей не знаю (здесь ассемблером заниматься не приходилось) но здравый смысл говорит что акулы Intel уж точно не обошли это дело стороной. Вероятно "целочисленные вычисления быстрее" становится легендой.

QRgb насколько я помню - просто unsigned int, возможно Вы имели ввиду QColor. Это хороший класс но заточен на значения [0..1], поэтому мне лично не подходит


Название: Re: Наследование от простой структуры
Отправлено: Alex Custov от Июня 27, 2010, 23:57
Ты пытаешься скрестить POD тип с классом C++.

В C++ структура - это класс, с доступом по-умолчанию "public"


Название: Re: Наследование от простой структуры
Отправлено: Alex Custov от Июня 27, 2010, 23:58
без констукторов не получится, т.к. в

Код
C++ (Qt)
RGB2 test4 = 0.0f;       // а так нельзя

уже используется конструктор (conversion by constructor)


Название: Re: Наследование от простой структуры
Отправлено: SABROG от Июня 28, 2010, 10:52
Ты пытаешься скрестить POD тип с классом C++.

В C++ структура - это класс, с доступом по-умолчанию "public"
Это не исключает того, что класс может быть или не быть POD типом.

Цитировать
Процессор PowerPC (big endian) не выпускается уже лет 5. Но он уже был RISC, значит все команды выполняются за 1 такт, значит умножение (и др. операции) с float происходят с той же скоростью что и с (long)int. Про новые процессоры Intel деталей не знаю (здесь ассемблером заниматься не приходилось) но здравый смысл говорит что акулы Intel уж точно не обошли это дело стороной. Вероятно "целочисленные вычисления быстрее" становится легендой.
Стремление ко всему новому это хорошо, но забывать о парке старых машин не стоит.

Цитировать
возможно Вы имели ввиду QColor. Это хороший класс но заточен на значения [0..1], поэтому мне лично не подходит
Да, его имел ввиду. Между 0.0 и 1.0 существует много промежуточных значений, это не бинарные true и false.


Название: Re: Наследование от простой структуры
Отправлено: sergek от Июня 28, 2010, 11:48
Думаю, проще всего обратиться к "библии" (Страуструп, 3-е специальное издание).

Цитировать
RGB test1 = { 0.0f };    // так можно
Такая форма инициализации обычно используется для массивов, допустима и для структур С (раздел 5.7). Поскольку эта форма инициализации была декларирована в C, то для совместимости оставлена и в C++. Однако так делать не рекомендуется, лучше использовать конструктор. Надо помнить, что инициализируются столько членов, сколько констант задано, остальные инициализируются нулем.
В C++, который предъявляет более жесткие требования по типизации выражений, такой возможности уже нет. Попробуйте, например, в структуру добавить член какого-нибудь класса (String, например),- компилятор даст ошибку.

Цитировать
RGB2 test2 = { 0.0f };   // так нельзя
Именно по причине, описанной чуть выше. Кстати, Страуструп предпочитает использование struct для классов, у которых по умолчанию все члены открыты (10.2.8 ). Вот повод с ним не согласиться (еще чуть-чуть, и я впаду в ересь.. 8) ) - в данном случае именно это и привело к непониманию результата. Если RGB это чистая структура C, то RGB2 - уже класс, и будьте добры подходить к нему с точки зрения C++! Чтобы не ошибиться, напишите class, а одна строчка с public Вам погоды не сделает.

Цитировать
RGB2 test3;
test3 = 0.0f;              // так можно
Это присвоение, используется перегруженный оператор "=". Нормальный ход.

Цитировать
RGB2 test4 = 0.0f;       // а так нельзя
А это копирующая инициализация (10.4.4.1). Для ее выполнения необходимо, чтобы в правой части стоял объект того же типа. Компилятор пытается правую часть преобразовать в RGB2 и не может, т.к. нет конструктора RGB2(float), который бы использовался для приведения типа. Если определить этот конструктор, то нужно определить и конструктор по умолчанию RGB2(), иначе объявление
Код:
RGB2 test3;
будет ошибкой.

Цитировать
Можно ли как-то устранить эти мелкие неудобства для RGB2 ?
Совет очевиден - используйте средства C++ для обеспечения тех операций, которые Вам нужны. Без конструкторов в приведенном примере не обойтись. Если хотите инициализировать объект другим объектом, нужно использовать конструктор копирования, если ходите выполнять присвоение объекта другого типа, выполняйте перегрузку оператора присвоения (10.4.4.1). Вот что по этому поводу пишет сам Страуструп: "Если классу требуется копирующая операция ..., ему вероятно потребуется конструктор ..., копирующий конструктор и копирющее присваивание".


Название: Re: Наследование от простой структуры
Отправлено: Igors от Июня 28, 2010, 11:58
Стремление ко всему новому это хорошо, но забывать о парке старых машин не стоит.
Конечно, но все хорошо в меру - учитывать специфику железа 10-летней давности - явный перебор  :)

Да, его имел ввиду. Между 0.0 и 1.0 существует много промежуточных значений, это не бинарные true и false.
Я понимаю, но у меня есть значения больше 1.0 (напр картинки в форматах hdr, exr и др)


Название: Re: Наследование от простой структуры
Отправлено: Igors от Июня 28, 2010, 12:27
Кстати, Страуструп предпочитает использование struct для классов, у которых по умолчанию все члены открыты (10.2.8 ). Вот повод с ним не согласиться (еще чуть-чуть, и я впаду в ересь.. 8) ) - в данном случае именно это и привело к непониманию результата. Если RGB это чистая структура C, то RGB2 - уже класс, и будьте добры подходить к нему с точки зрения C++! Чтобы не ошибиться, напишите class, а одна строчка с public Вам погоды не сделает.
Как и Страуструп, я предпочитаю использовать struct, ясно показывая что все члены открыты. В инженерных расчетах таких классов довольно много. Они не подходят для наследования, не имеют виртуалов и.т.п., но работы делают много. Если не ошибаюсь, Страуструп называет их "конкретными" классами.
По поводу class: когда я вижу класс типа

Код
C++ (Qt)
class RGB {
public:
float getRed( void ) const { return r; }
void setRed ( float _r ) { r = _r; }
...
private:
float r, g, b;
};
 
Я вижу что написавший "следует известным образцам" и никак не пытается осмыслить написанное  :) Ну зачем в данном случае делать r, g, b private? Это имело бы резоны для различных цветовых моделей, когда r, g, b могут интерпретироваться по-разному, но никак не здесь.

Мда, придется все-таки добавить конструкторы. Спасибо за ответы, приятно видеть знание классики.


Название: Re: Наследование от простой структуры
Отправлено: m_ax от Июня 28, 2010, 15:51
Я бы вообще забил на наследование.. Нафига?
Код
C++ (Qt)
#include <iostream>
 
using namespace std;
 
struct RGB {
   float r, g, b;
};
 
struct RGB2 {
   RGB2() { r = 0; g = 0; b = 0; }
 
   RGB2(const RGB2 &other) {
       r = other.r;
       g = other.g;
       b = other.b;
   }
   RGB2(float f) {
       r = g = b = f;
   }
 
   RGB2(const RGB &other) {
       r = other.r;
       g = other.g;
       b = other.b;
   }
 
 
   RGB2 & operator = ( float f )  {
       r = g = b = f;
       return *this;
   }
 
   operator RGB() const {
       RGB rgb;
       rgb.r = r;
       rgb.g = g;
       rgb.b = b;
       return rgb;
   }
 
   float r;
   float g;
   float b;
};
 
void func(const RGB &rgb) {
   cout << "r = " << rgb.r << endl;
   cout << "g = " << rgb.g << endl;
   cout << "b = " << rgb.b << endl;
}
 
 
int main()
{
   RGB test1 = { 0.0f };
 
   RGB2 test2 = test1;
 
   RGB2 test3 = 0.4f;
 
   func(test3); // Опа, работает! Хотя передаём объект RGB2, вместо RGB.. (operator RGB() const)
 
   return 0;
}
 

Я бы сделал как-то так...
 


Название: Re: Наследование от простой структуры
Отправлено: sergek от Июня 29, 2010, 09:57
Я бы сделал как-то так...
Боже упаси Вас так делать!

Я бы вообще забил на наследование.. Нафига?
Во-первых, для того, чтобы не напороться на необъяснимые ошибки, когда кто-то (в том числе и Вы) изменит класс RGB.
Во-вторых, чтобы не дублировать код. Стоит унаследовать RGB2 от RGB, как код становится короче на десяток строк (не нужен будет оператор преобразования в RGB и члены r,g,b):
Код:
/*    operator RGB() const {
        RGB rgb;
        rgb.r = r;
        rgb.g = g;
        rgb.b = b;
        return rgb;
    }
 
    float r;
    float g;
    float b;
*/
В-третьих, чтобы можно было манипулировать объектами разного типа с помощью указателей на базовый класс, используя свойство полиморфизма.


Название: Re: Наследование от простой структуры
Отправлено: Igors от Июня 29, 2010, 10:49
Я думал не наследоваться, конечно это развязывает мне руки с RGB2. Но с др. стороны я рискую получить проблемы с разными alignment для структур - а с наследованием это исключено


Название: Re: Наследование от простой структуры
Отправлено: m_ax от Июня 29, 2010, 23:32
Цитировать
...
В-третьих, чтобы можно было манипулировать объектами разного типа с помощью указателей на базовый класс, используя свойство полиморфизма.
sergek
Вы, конечно же правы) Тут не поспоришь и я понимаю всю важность и мощь ООП, но не кажется ли Вам в даннном конкретном случае смешным наследоваться от сомнительной структуры, которая имеет всего три члена?)) К тому же, судя по всему менять её никто не намерен))
Видимо, единственный аргумент для такого хода, озвученный Igors:
Цитировать
... я рискую получить проблемы с разными alignment для структур - а с наследованием это исключено
хотя я так и не раскурил где там могут возникнуть проблемы, ну да ладно))

Кстати, Igors:
Цитировать
Я вижу что написавший "следует известным образцам" и никак не пытается осмыслить написанное   Ну зачем в данном случае делать r, g, b private? Это имело бы резоны для различных цветовых моделей, когда r, g, b могут интерпретироваться по-разному, но никак не здесь.

А вот Троли с Вами бы не согласились)) Если посмотреть на реализацию не малоизвестного класса QPoint (QPointF) ... Там вообще всего два члена x, y. Почему они его в виде структуры не оформили, вроде Вашей RGB? Это же проще))
 



Название: Re: Наследование от простой структуры
Отправлено: Igors от Июня 30, 2010, 11:07
А вот Троли с Вами бы не согласились)) Если посмотреть на реализацию не малоизвестного класса QPoint (QPointF) ... Там вообще всего два члена x, y. Почему они его в виде структуры не оформили, вроде Вашей RGB? Это же проще))
Да он вообще слабо написан, нет многих нужных ф-ций (напр. length, dot, product) так что это не то место где надо учиться у Qt


Название: Re: Наследование от простой структуры
Отправлено: SABROG от Июня 30, 2010, 23:19
А вот Троли с Вами бы не согласились)) Если посмотреть на реализацию не малоизвестного класса QPoint (QPointF) ... Там вообще всего два члена x, y. Почему они его в виде структуры не оформили, вроде Вашей RGB? Это же проще))
Да он вообще слабо написан, нет многих нужных ф-ций (напр. length, dot, product) так что это не то место где надо учиться у Qt

Поищи в классе QVector2D.


Название: Re: Наследование от простой структуры
Отправлено: Igors от Июля 01, 2010, 04:27
Поищи в классе QVector2D.
Получше но тоже бедненько - поворотов нет, ф-ции отражения от нормали нет, расстояния до отрезка нет и.т.д. Ладно, это уже оффтоп, умолкаю  :)