Перегрузка опер

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

like-nix
Сообщения: 8
Зарегистрирован: 13 окт 2008, 16:01

Всем привет!

Помогите разобраться с перегрузкой операторов.
Хочу реализовать класс который будет представлять тип double с определенной точностью. Еще нужна возможность преобразования в тип int и double.

Код: Выделить всё

template <unsigned int precision>
class SDouble
{
public:
    // uninitialized
    SDouble ();
    // construction
    SDouble (double fX);
    SDouble (int fX);
    //copy constructor
    SDouble (const SDouble& rkSD);
    
    // assignment
    inline SDouble& operator= (const SDouble&);
    
    // comparison
    bool operator== (const SDouble&) const;
    bool operator!= (const SDouble&) const;
    bool operator<  (const SDouble&) const;
    bool operator<= (const SDouble&) const;
    bool operator>  (const SDouble&) const;
    bool operator>= (const SDouble&) const;
    
    //unary operations
    inline SDouble operator-() const;
    inline SDouble operator+() const;
    
    //arithmetic operations
    inline SDouble operator+ (const SDouble&) const;
    inline SDouble operator- (const SDouble&) const;
    inline SDouble operator* (const SDouble&) const;
    inline SDouble operator/ (const SDouble&) const;
    
    // arithmetic updates
    inline SDouble& operator+= (const SDouble&);
    inline SDouble& operator-= (const SDouble&);
    inline SDouble& operator*= (const SDouble&);
    inline SDouble& operator/= (const SDouble&);
    
    //arithmetic operations 
    template <unsigned int precision>
    friend SDouble<precision> operator+ (double s_value, const SDouble<precision>&);
    template <unsigned int precision>
    friend SDouble<precision> operator- (double s_value, const SDouble<precision>&);
    template <unsigned int precision>
    friend SDouble<precision> operator* (double s_value, const SDouble<precision>&);
    template <unsigned int precision>
    friend SDouble<precision> operator/ (double s_value, const SDouble<precision>&);
    
    //type cast
    operator int();
    operator double();
    
    //value
    double getValue() const;
private:
    
    double supp_val_precision(double) const;
    
private:
    double m_Value;
};
При попытке выполнить код:

Код: Выделить всё

    SDouble<4> sd(7.12);
    SDouble<4> sdr =-sd + 5.0;
Получаю:

Код: Выделить всё

1>d:\programming\freelance\mathematic_library\release\my_new_library001\my_new_library\main.cpp(443) : error C2666: 'SDouble<degree>: :o perator +' : 3 overloads have similar conversions
1>        with
1>        [
1>            degree=4
1>        ]
1>        d:\programming\freelance\mathematic_library\release\my_new_library001\my_new_library\sdouble.hpp(39): could be 'SDouble<degree> SDouble<precision>: :o perator +(const SDouble<precision> &) const'
1>        with
1>        [
1>            precision=4
1>        ]
1>        or       'built-in C++ operator+(int, double)'
1>        or       'built-in C++ operator+(double, double)'
1>        while trying to match the argument list '(SDouble<precision>, double)'
1>        with
1>        [
1>            precision=4
1>        ]
Аватара пользователя
Airhand
Сообщения: 239
Зарегистрирован: 06 окт 2005, 16:21
Откуда: Dnepropetrovsk

Тут действительно неоднозначность: 5.0 - это int, double или SDouble ? Попробуй явно указать тип: SDouble(5.0) или double(5.0).
Оптимизация по скорости:
#define while if
Оптимизация по размеру:
#define struct union
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Airhand, ты как обычно невнимателен. Ты дал один из правильных ответов, но объяснения неверны и лишь сбивают с толку.

Начнём с небольшого экскурса в теорию. Написав "5.0", мы говорим компилятору, что это число с плавающей точкой. Более того, я уточню, мы говорим, что это число типа double, так как мы ничего не написали в конце литерала (например если бы мы дописали букву f, то сказали ли бы компилятору, что это выражение типа float).

Таким образом, в данной ситуации литерал "5.0" не может быть интерпретирован, как int, Airhand. Однозначность возникает в другом, а именно в том, что операцию SDouble<degree>: :o perator+ можно разрешить тремя разными способами.

Код: Выделить всё

could be 'SDouble<degree> SDouble<precision>: :o perator +(const SDouble<precision> &) const'
or       'built-in C++ operator+(int, double)'
or       'built-in C++ operator+(double, double)'
То есть, либо "5.0" конвертнуть в SDouble с помощью соответствующего конструктора, либо вот этими двумя операторами приведения типов:

Код: Выделить всё

    //type cast
    operator int();
    operator double();
сконвертировать правый операнд в double или int и вызвать build-in С++ operator.

Действительно, если мы напишем SDouble(5.0), то поможем компилятору выбрать первый вариант вызова. Однако, когда ты начал давать объяснения, Airhand, то смотрел уже на второй и третий варианты вызова, причём смотрел невнимательно. Обрати внимание, у компилятора нет сомнений в отношении правого операнда (справа стоит 5.0), так как и во второй, и в третьей строке, в правой части написан double. У него есть сомнения в отношении левого операнда, так как SDouble можно интерпретировать и как int, и как double, благодаря двум операторам приведения.

Собственно, из всего этого, следует, что если мы напишем (double)sd, а ещё лучше, если воспользуемся С++ оператором приведения к типу и напишем static_cast<double>(sd), то у нас тоже всё заработает. Это и будет второй вариант решения данной проблемы.

Спешу также отметить, что и первое, и второе решение проблемы вполне честное. Но если делать по-хорошему, то исправлять надо сам класс для того, чтобы таких неоднозначностей не возникало. Это будет гораздо более правильным, хоть и более трудоёмким решением задачи.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
Airhand
Сообщения: 239
Зарегистрирован: 06 окт 2005, 16:21
Откуда: Dnepropetrovsk

Лучше не использовать форму (5.0)SDouble, а использовать конструктор SDouble(5.0).
Оптимизация по скорости:
#define while if
Оптимизация по размеру:
#define struct union
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

&quot писал(а):(5.0)SDouble
Это ты так экзотически записал приведение к типу? Чем использование конструктора лучше? Можешь привести конкретные аргументы?

Я считаю, что оба варианта примерно равноценны и оба не решают проблему целиком. Самое правильное решение - это:
&quot писал(а):...исправлять надо сам класс для того, чтобы таких неоднозначностей не возникало. Это будет гораздо более правильным, хоть и более трудоёмким решением задачи.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
Airhand
Сообщения: 239
Зарегистрирован: 06 окт 2005, 16:21
Откуда: Dnepropetrovsk

Приведение типа хуже конструктора тем, что в конструкторе можно описать целую кучу действий, а приведение типа - это простое приведение кучи байт к типу.
Оптимизация по скорости:
#define while if
Оптимизация по размеру:
#define struct union
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

&quot писал(а):приведение типа - это простое приведение кучи байт к типу
Ты меня очередной раз поражаешь своей глубиной знаний :) Ну и конечно же своей внимательностью. Если бы ты прочёл полностью мой первый пост, то такой бы ерунды точно не написал, даже если бы раньше ничего о приведении типов не знал. А в следствии того, что ты меня не читаешь, то как не знал раньше, так и не знаешь сейчас :)

Специально для Airhand откопирую сюда фрагмент из моего первого поста:
&quot писал(а):либо вот этими двумя операторами приведения типов:

cpp Код:

//type cast
operator int();
operator double();

сконвертировать правый операнд в double или int и вызвать build-in С++ operator.
Оператор приведения к типу это тоже метод класса. Нет ничего такого, что бы можно было сделать в конструкторе, но не сделать в операторе приведения к типу.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
Airhand
Сообщения: 239
Зарегистрирован: 06 окт 2005, 16:21
Откуда: Dnepropetrovsk

Romeo
Ты спросил:
Чем использование конструктора лучше? Можешь привести конкретные аргументы?
Я ответил. Я понимаю, что лучшая защита - это нападение. Ты выкрутился и облил меня в очередной раз грязью. Дескать ты говорил про операции класса приведения типов, а не про общие.
Лучше писать явно конструктор, чем оставлять компилятору на выбор. Понятнее потом будет тому, кто будет читать прогу.
Оптимизация по скорости:
#define while if
Оптимизация по размеру:
#define struct union
atavin-ta
Сообщения: 585
Зарегистрирован: 30 янв 2009, 06:38

Ну если кто-то не понимт приведения типов, то это его проблемы.
--------------------------------------------------------------------------------
Добавлено сообщение
--------------------------------------------------------------------------------
&quot писал(а):Спешу также отметить, что и первое, и второе решение проблемы вполне честное. Но если делать по-хорошему, то исправлять надо сам класс для того, чтобы таких неоднозначностей не возникало. Это будет гораздо более правильным, хоть и более трудоёмким решением задачи.
Где найти текст о том, как это делается ? Мне бы тоже пригодилось, а то мне приходится часто в этих целях втыкать операторы приведения к типу.
Вопрос: "Почему вы все сионисты? Нельзя ли писать на чём то другом?".
Ответ: "Писать можно на чём угодно. Но зачем же так себя ограничивать? Пиши на С!".
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

&quot писал(а):Дескать ты говорил про операции класса приведения типов, а не про общие.
Airhand, где граница между операциями приведения класса и общими? Не старайся, ты её не сможешь указать, так как её нет.

Я не давал повода расценивать свои слова двояко. Я привёл конкретный кусок кода, а именно (double)sd. В этой строке нет никакой двусмысленности - здесь всегда будет вызван оператор приведения к типу. Никогда и не при каких условиях здесь не будет "простого приведение кучи байт к типу". Твоя проблема в том, что ты этого не знаешь.
&quot писал(а):Лучше писать явно конструктор, чем оставлять компилятору на выбор.
У компилятора нет выбора. Записав так, мы будем ВСЕГДА иметь одно и то же поведение компилятора - это гарантия стандарта. Поведения компилятора не будет зависеть ни от времени года, ни от атмосферного давления, ни от индекса Доу-Джонса. Это требование СТАНДАРТА.

Слушай, если бы мне кто-то твердил днём и ночью про какой-то там стандарт, который я не знаю, но должен знать, как специалист, то я бы его уже давно прочёл. Но ты, молодец, Airhand. Ты упорен до конца в своём стремлении быть необразованным.
&quot писал(а):Понятнее потом будет тому, кто будет читать прогу.
Понятней будет тому, кто знает С++. Остальные нас не интересуют.

Возвращаясь в вопросу. У конструктора нет никаких преимуществ перед оператором присваивания!
&quot писал(а):Где найти текст о том, как это делается ? Мне бы тоже пригодилось, а то мне приходится часто в этих целях втыкать операторы приведения к типу.
Оператор приведения к типу не есть зло. Для того, чтобы решить указанную проблему на уровне архитектуры приложения, следует подобрать такой набор операторов и конструкторов класса, который бы обеспечивал однозначную трактовку подобных синтаксических конструкций. Конкретного алгоритма по которому это можно сделать нет. Здесь придётся идти методом проб и ошибок, добиваясь гармонии.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Закрыто