Russian Qt Forum
Января 19, 2025, 15:16 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Наследование от простой структуры  (Прочитано 15452 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Июня 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 ?

Спасибо
Записан
SABROG
Гость
« Ответ #1 : Июня 26, 2010, 14:25 »

Ты пытаешься скрестить POD тип с классом C++. Интерфейс класса написать можно, но к этому интерфейсу придется приводить тип, чтобы воспользоваться его методами, но как я понял приведение типов тебя не устраивает по какой-то причине.

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

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Июня 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], поэтому мне лично не подходит
Записан
Alex Custov
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2063


Просмотр профиля
« Ответ #3 : Июня 27, 2010, 23:57 »

Ты пытаешься скрестить POD тип с классом C++.

В C++ структура - это класс, с доступом по-умолчанию "public"
Записан
Alex Custov
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2063


Просмотр профиля
« Ответ #4 : Июня 27, 2010, 23:58 »

без констукторов не получится, т.к. в

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

уже используется конструктор (conversion by constructor)
Записан
SABROG
Гость
« Ответ #5 : Июня 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.
Записан
sergek
Гипер активный житель
*****
Online Online

Сообщений: 872


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #6 : Июня 28, 2010, 11:48 »

Думаю, проще всего обратиться к "библии" (Страуструп, 3-е специальное издание).

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

Цитировать
RGB2 test2 = { 0.0f };   // так нельзя
Именно по причине, описанной чуть выше. Кстати, Страуструп предпочитает использование struct для классов, у которых по умолчанию все члены открыты (10.2.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). Вот что по этому поводу пишет сам Страуструп: "Если классу требуется копирующая операция ..., ему вероятно потребуется конструктор ..., копирующий конструктор и копирющее присваивание".
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Июня 28, 2010, 11:58 »

Стремление ко всему новому это хорошо, но забывать о парке старых машин не стоит.
Конечно, но все хорошо в меру - учитывать специфику железа 10-летней давности - явный перебор  Улыбающийся

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

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Июня 28, 2010, 12:27 »

Кстати, Страуструп предпочитает использование struct для классов, у которых по умолчанию все члены открыты (10.2.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 могут интерпретироваться по-разному, но никак не здесь.

Мда, придется все-таки добавить конструкторы. Спасибо за ответы, приятно видеть знание классики.
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #9 : Июня 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;
}
 

Я бы сделал как-то так...
 
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
sergek
Гипер активный житель
*****
Online Online

Сообщений: 872


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #10 : Июня 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;
*/
В-третьих, чтобы можно было манипулировать объектами разного типа с помощью указателей на базовый класс, используя свойство полиморфизма.
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #11 : Июня 29, 2010, 10:49 »

Я думал не наследоваться, конечно это развязывает мне руки с RGB2. Но с др. стороны я рискую получить проблемы с разными alignment для структур - а с наследованием это исключено
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #12 : Июня 29, 2010, 23:32 »

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

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

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

Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #13 : Июня 30, 2010, 11:07 »

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

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

Поищи в классе QVector2D.
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.075 секунд. Запросов: 23.