Як перевантажити оператора ++ двома різними способами для постфікса a ++ та префікса ++ a?


110

Як перевантажити оператора ++ двома різними способами для постфікса a++та префікса ++a?



Відповіді:


165

Має виглядати так:

class Number 
{
    public:
        Number& operator++ ()     // prefix ++
        {
           // Do work on this.   (increment your object here)
           return *this;
        }

        // You want to make the ++ operator work like the standard operators
        // The simple way to do this is to implement postfix in terms of prefix.
        //
        Number  operator++ (int)  // postfix ++
        {
           Number result(*this);   // make a copy for result
           ++(*this);              // Now use the prefix version to do the work
           return result;          // return the copy (the old) value.
        }
}; 

15
Цей код також показує різницю в продуктивності префікса та постфікса. Якщо об'єкт, який ви повертаєте, не вписується в регістр процесора, тоді ви робите дорогу операцію копіювання. Це добре, якщо вам потрібно використовувати попередньо збільшене значення, але якщо цього не зробити, постфікс набагато краще. Прикладом може бути ітератор, де ви зазвичай використовуєте: for (pos = c.begin (); ...; ++ pos) {} замість pos ++
Ерік

22
@Eric: Ви маєте це правильно виправити через речення посередині, де ви змішуєте. Його префікс краще.
Мартін Йорк

6
Чому Number operator++ (int)приймають в intякості параметра , навіть якщо ви не використовуєте його?
Шон Летендре

10
@SeanLetendre: Фактично не приймає параметр int. Це підроблений параметр. Але дизайнерам мови C ++ довелося визначити спосіб розмежування визначень префікса та постфікса. Це проектне рішення, яке вони прийняли.
Мартін Йорк

2
@EnricoMariaDeAngelis: синтаксис розрізняє два. ++xє префіксом і, таким чином, дзвонить у operator++() той час x++як постфікс, і таким чином дзвонитьoperator++(int)
Мартін Йорк

34

Різниця полягає в тому, який підпис ви обираєте для свого перевантаження operator ++.

Цитований із відповідної статті з цього приводу у поширених запитаннях C ++ (перегляньте там докладніші відомості):

class Number {
  public:
    Number& operator++ ();     // prefix ++: no parameter, returns a reference
    Number  operator++ (int);  // postfix ++: dummy parameter, returns a value
};

PS: Коли я дізнався про це, усе, що я побачив, спочатку був параметр фіктивного типу, але різні типи повернення насправді цікавіші; вони можуть пояснити, чому ++xце вважається більш ефективним, ніж x++ загалом .


17

У вас є два способи перевантажити два (префікс / постфікс) ++ операторів для типу T:

Метод об'єкта:

Це найпростіший спосіб, використовуючи «загальну» ідіому OOP.

class T
{
    public :
        T & operator++() // ++A
        {
            // Do increment of "this" value
            return *this ;
        }

        T operator++(int) // A++
        {
           T temp = *this ;
           // Do increment of "this" value
           return temp ;
        }
} ;

Об'єкт не є членом:

Це ще один спосіб зробити це. Поки функції знаходяться в тій самій області імен, що і об'єкт, на який вони також посилаються, вони будуть враховані, коли компілятор буде шукати fonction для обробки ++t ;або t++ ;коду:

class T
{
    // etc.
} ;


T & operator++(T & p_oRight) // ++A
{
   // Do increment of p_oRight value
   return p_oRight ;
}

T operator++(T & p_oRight, int) // A++
{
   T oCopy ;
   // Copy p_oRight into oCopy
   // Do increment of p_oRight value
   return oCopy ;
}

Важливо пам’ятати, що з точки зору C ++ (включаючи точку зору компілятора C ++), ці нечленні функції все ще є частиною інтерфейсу T (доки вони знаходяться в одному просторі імен).

Є дві потенційні переваги позначення функції не члена:

  • Якщо вам вдасться зашифрувати їх, не зробивши їх товаришем з Т, тоді ви збільшили інкапсуляцію Т
  • ви можете застосувати це навіть до класів або структур, кодом яких ви не володієте. Це ненав'язливий спосіб покращення інтерфейсу об'єкта без зміни його декларації.

1

Заявіть так:

class A
{
public:
    A& operator++();    //Prefix (++a)
    A operator++(int); //Postfix (a++)

};

Впроваджуйте належним чином - не возиться з тим, що всі знають, що вони роблять (приріст потім використовуйте, використовуйте потім приріст).


-2

Я знаю, що пізно, але у мене була така ж проблема і я знайшов більш просте рішення. Не зрозумійте мене неправильно, це те саме рішення, що і перше (опублікував Мартін Йорк). Це просто трохи простіше. Трошки. Ось:

class Number
{
        public:

              /*prefix*/  
        Number& operator++ ()
        {
            /*Do stuff */
            return *this;
        }

            /*postfix*/
        Number& operator++ (int) 
        {
            ++(*this); //using the prefix operator from before
            return *this;
        }
};

Наведене вище рішення трохи простіше, оскільки воно не використовує тимчасовий об'єкт у методі postfix.


6
Це не стандартно. Оператор postfix ++ повинен повертати те, що було значення до збільшення, а не після.
Куїлін Лі

Ця відповідь невірна. Тимчасовий обов'язковий.
Rian Quinn
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.