LinuxForum.Fans
Тема

C++ Лафоре, Перегрузка унарных операторов

Автор: aivs 7 сообщений 2715 просмотров
#236744

Изучаю С++ по книге Лафоре, прошел перегрузку операций, но при решении Упражнений появился вопрос.
Вот такой коротенький пример, нужно перегрузить унарную операцию ++, постфиксную запись и префиксную.
Есть условие! Задаю число, и начинаю прибавлять к нему по единице, когда доходит до 10, счет начиниется сначала.

text
    Counter operator++(int)
    { 
        count++;
        if (count >9)
            count= count - 10;
        return Counter(count);
    }

Проблема в том, что если есть условие, то операция c2=c1++ работает не верно, я ожидаю что в с2 запишется значение с1, а затем с1 инкрементируется, но получается, что с1 сначала инкрементируется, а затем записывается в с2, как будто выполнятеся с2=++с1.

Если никакого условия не ставить

text
  Counter operator++(int)
    { return Counter(count++);}

то все работает как надо.

Подскажите как заставить работать условие моем варианте???

Полный листинг

text
#include <iostream>
using namespace std;
/////////////////////////////
class Counter
{
private:
    int count;
public:
    Counter(): count(0)
    {}
    Counter(int c): count(c)
    {}
    int get_count()
    { return count; }
    
    Counter operator++()
    { return Counter(++count);}
    
    //Работает
    //Counter operator++(int)
    //{ return Counter(count++);}
    
    Counter operator++(int)
    { 
        count++;
        if (count >9)
            count= count - 10;
        return Counter(count);
    }
    
};
//////////////////
int main()
{
    Counter c1=9, c2;

// Вывод заданных значений cout << "\nc1 = " << c1.get_count(); cout << "\nc2 = " << c2.get_count(); // Сначала значение с1 присваивается с2, затем с1 инкрементируется c2=c1++; // Ожидается, что с1 = 0, с2 = 9 cout << "\nc1 = " << c1.get_count(); cout << "\nc2 = " << c2.get_count() << endl; return 0; }

#236753
text
   Counter operator++(int)
    { 
        int rv=count;
        count++;
        if (count >9)
            count= count - 10;
        return Counter(rv);
    }

ИМХО идея ясна

#236772

Как обычно! все гениальное просто!
Сначала нужно возвращать старое значение, а потом уже в объекте инкементировать переменную.
Спасибо!

#236777

aivs, вообще-то лучше не трогать постфиксные ++ и --, с ними вы проблем оберётесь немеренно. Эти операции введены в Си потому, что на некоторых процессорах того времени действительно была операция постфиксного инкремента, и работала она очень быстро. На сегодняшних процессорах такая операция вроде как тоже "есть" (она "реализована" переименованием регистров), но работает это всё исключительно только для целых, и исключительно только для РОН. В FPU, MMX, SSE такого нет, ЕМНИП.

Я уж не говорю про нетривиальные классы, которые будут выделять/освобождать Over9000 кусков памяти на таком тривиальном коде

text
for(i = 0; i; i++);

лучше сделайте private затычку, что-бы писать такой кривой код было невозможно.
(тоже самое касается обычно и перезагрузки operator=() с конструктором копий)

#236778

Спасибо, учту замечания!

#236818

drBatty, не совсем согласен... маст-хев, например, для итераторов (но для каких-нить толстых итераторов (вроде по дереву) лучше конечно не реализовывать или писать толстый ворнинг), подобный счётчик тоже имеет право на существование.
а оператор= почти всегда возвращает ссылку...
кста, тут префиксный тоже по-хорошему должен возвращать ссылку.

#236827
Fat-Zer написал:
не совсем согласен... маст-хев, например, для итераторов (но для каких-нить толстых итераторов (вроде по дереву) лучше конечно не реализовывать или писать толстый ворнинг), подобный счётчик тоже имеет право на существование.

дык у меня выше как раз и есть типичный итератор. Вот зачем там использовать постфиксный инкремент? Наворотить 100500 строк лишнего кода, в надежде, что оптимизирующий компилятор его выкинет? Так в С++ и так для оптимизирующего компилятора полно работы, с которой он как известно полностью не справляется.

Fat-Zer написал:
а оператор= почти всегда возвращает ссылку...

ну и что? Что возвращает operator=() мало кому известно, а кому известно, тех это не очень волнует. Куда как важнее, что сделает этот оператор с *this. А этому *this изрядно поплохеет, ежели сработает оператор копирования по умолчанию, который как известно копирует бит-в-бит, совершенно не заботясь о структуре вашего класса. С конструктором копий та же самая беда. (похожие грабли и с невиртуальным деструктором).

Fat-Zer написал:
кста, тут префиксный тоже по-хорошему должен возвращать ссылку.

ссылку конечно нужно возвращать везде, где это только возможно (в операторе + это обычно невозможно/нерационально), но дело таки не в этом - перезагрузка нужна для того, что-бы подняться над деталями реализации, а как вы поднимитесь, если вам нужно каждую секунду помнить о "толщине" этой самой реализации? Проще всего взять, и запретить постфиксные операции и копирование там, где это не нужно. И если копирование где-то таки нужно, то уж где нужны постфиксные операции - не представляю совершенно. Ибо работают они исключительно по вашей схеме, т.е. очень не эффективно.

ЗЫЖ кстати, а на что вы тут ссылку собрались передавать? На стековый объект? Дык он уничтожен будет - UB вам обеспечено. В отличие от варианта с префиксной операцией, в которой вы можете передать ссылку на *this, ибо *this уничтожено не будет. Ещё один недостаток постфиксных операций...

Войдите или зарегистрируйтесь, чтобы ответить.