Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > Класс для работы с дробями


Автор: Superklug 23.2.2010, 20:30
Доброго времени суток!
Пишу класс для работы с дробями.. Хотелось бы добиться полной совместимости с int. 
Код

class drob
{
private:
    int ch, zn;
    int NOD( int a, int b);
    void sokr();

public:
    drob( int tch = 0, int tzn = 1 );

    int znam();
    void znam( int tzn);

    int chisl();
    void chisl( int tch);

    friend bool operator>(drob d1, drob d2);
    friend bool operator<(drob d1, drob d2);
    friend bool operator>=(drob d1, drob d2);
    friend bool operator<=(drob d1, drob d2);
    friend bool operator==(drob d1, drob d2);
    friend bool operator!=(drob d1, drob d2);

    friend drob operator+(drob d1, drob d2);
    friend drob operator-(drob d1, drob d2);
    friend drob operator*(drob d1, drob d2);
    friend drob operator/(drob d1, drob d2);
    
    drob operator+=(drob d);
    drob operator-=(drob d);
    drob operator*=(drob d);
    drob operator/=(drob d);

    operator int();
}


В случае если пытаюсь написать что-нибудь вроде:
Код

drob a(7,3);
int b = 5;
int c = b + a;

Возникает ошибка: error C2666: 'operator +' : 2 overloads have similar conversions
Как избежать этого?


Автор: Ockonal 23.2.2010, 20:41
Да, я тут писал класс для работы с дробями: http://wincode.org.ua/?p=245
----
А по вопросу конкретно: http://kbalertz.com/106392/C2666-Error-Generated-Overloaded-Operator.aspx

Автор: Superklug 23.2.2010, 21:16
Ockonal, ваш класс не совсем то, что мне нужно... 
Мне бы хотелось добиться такого, что работать с моим классом вместе с int будет так же просто как и double вместе с int...

На сколько я понимаю ошибка заключается в том, что компилятор не может выбрать между int+drob и int+int..
Можно конечно всегда явно указывать (int), но как-то же можно реализовать иначе?

Автор: Леопольд 24.2.2010, 09:12
Цитата(Superklug @  23.2.2010,  20:30 Найти цитируемый пост)
Возникает ошибка: error C2666: 'operator +' : 2 overloads have similar conversions

Добавь 
Код

template<typename T>
drob operator+(T d1, drob d2){
    return drob(d1) + d2;
}


Добавлено через 9 минут и 9 секунд
Цитата(Superklug @  23.2.2010,  21:16 Найти цитируемый пост)
компилятор не может выбрать между int+drob и int+int

Так и есть. Компилятор перед выбором.

operator+(drob(b), a)
    или
b + a.operator int()

Добавлено через 11 минут и 25 секунд
Оба выражения включают в себя по одному пользовательскому преобразованию и поэтому равнозначны. Функция, где не будет таких неявных преобразований будет препочтительнее тем двум.

Автор: bsa 24.2.2010, 12:23
Superklug, operator int() лишний. От него лучше избавиться, так как из-за него будет ОЧЕНЬ много проблем.

Добавлено через 1 минуту и 11 секунд
Я бы вместо drob operator +=(drob x) писал бы drob& operator +=(const drob &x) - меньше лишних операций копирования.

Автор: Superklug 24.2.2010, 15:37
Леопольд, спасибо! Сейчас попробую разобраться...


bsa, я б с радостью избавился... Но не умею по другому. Как без него сделать работоспособным след код:
Код

drob d(5,2);
int n = d;


А по поводу ссылок знаю.. Просто на форуме заморачиваться не стал smile

Автор: Superklug 24.2.2010, 15:58
Леопольд, выходит надо добавлять по два шаблона для каждого оператора? Например:
Код

template<typename T> drob operator+(T d1, drob d2);
template<typename T> drob operator+(drob d1, T d2);


И еще, если оставить ф-ю drob operator+(drob d1, drob d2), то та ошибка возникает снова. Можно операции реализовывать непосредственно в шаблонных функциях..

Я правильно мыслю? Или усложнил все)

Автор: bsa 24.2.2010, 16:59
Цитата(Superklug @  24.2.2010,  15:37 Найти цитируемый пост)
Как без него сделать работоспособным след код
А не надо его делать работоспособным. Так как эта функциональность провоцирует ошибки.
Более того, в библиотеке boost во всех типах, которые можно привести к bool (например, умные указатели - проверка на NULL), делают это через оператор преобразования к указателю на метод этого типа. И делают это специально, чтобы не дай бог случилось, что кто-то случайно ошибся и компилятор это молча проглотил...


Цитата(Superklug @  24.2.2010,  15:58 Найти цитируемый пост)
Я правильно мыслю? Или усложнил все) 
Я тебе уже написал про оператор преобразования. Все эти и будущие проблемы именно в нем.

Автор: Леопольд 24.2.2010, 17:48
Цитата(Superklug @  24.2.2010,  15:58 Найти цитируемый пост)
Леопольд, выходит надо добавлять по два шаблона для каждого оператора?

Два не надо, в случае с a + b будет вызов drob operator+ (a, drob(b))
Я лишь показал как можно обойти проблему. Однако operator int() ещё может тебе напакостить. Можно где-нибудь легко получить двойное пользовательское преобразование, к примеру:
Код
#include <iostream>

struct Test1{
    operator char() {
        std::cout<<"Test1"<<std::endl;
        return 0;
    }
};
//struct Test2: public Test1{ а так будет работать, только не забудь закомментировать строку ниже.
struct Test2{
    Test2(){}
    operator Test1() {
        std::cout<<"Test2"<<std::endl;
        return Test1();
    }
};
void foo(char){}

int main()
{
    foo(Test2());
    return 0;
}


Но лучше просто убарть operator int(), как уже заметил bsa:

Код

#include <iostream>

class drob
{
private:
    int ch, zn;
    static int abs(int a){
        return a>0 ? a : -a;
    }
    static int NOD(int a, int b){
        a = abs(a);
        b = abs(b);
        while (a != b){
            if (a > b)
                a -= b;
            else
                b -= a;
        }
        return a;
    }

public:
    drob(int tch = 0, int tzn = 1 ):ch(tch/NOD(tch, tzn)), zn(tzn/NOD(tch, tzn)) {}

    int znam() const{
        return zn;
    }
    void znam(int tzn){
        zn = tzn;
    }

    int chisl() const{
        return ch;
    }
    void chisl(int tch){
        ch = tch;
    }


    friend drob operator+(const drob& d1, const drob& d2);
};

drob operator+(const drob& d1, const drob& d2){
    int ch = d1.ch * d2.zn + d2.ch * d1.zn;
    int zn = d1.zn * d2.zn;
    return drob(ch, zn);
}

std::ostream& operator<< (std::ostream& out, const drob& d){
    out<<d.chisl()<<'/'<<d.znam();
    return out;
}

int main()
{
    drob a(10,12);
    std::cout<<a<<std::endl;
    drob b = -2 + a; // здесь сработает конструктор - drob(2)
    std::cout<<b<<std::endl;
    return 0;
}

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