วิธีการโอเวอร์โหลดตัวดำเนินการ ++ ในสองวิธีที่แตกต่างกันสำหรับ postfix a ++ และคำนำหน้า ++ a


110

วิธีการโอเวอร์โหลดตัวดำเนินการ ++ ในสองวิธีที่แตกต่างกันสำหรับ postfix a++และคำนำหน้า++a?


1
เกี่ยวข้อง: stackoverflow.com/questions/3181211/…
kennytm

เวอร์ชัน "ทำไมจึงเป็นไวยากรณ์": stackoverflow.com/questions/3574831/…
Ciro Santilli 郝海东冠状病六四事件法轮功

คำตอบ:


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
รหัสนี้ยังแสดงคำนำหน้าเทียบกับความแตกต่างของประสิทธิภาพ postfix หากวัตถุที่คุณส่งคืนไม่พอดีกับทะเบียน CPU แสดงว่าคุณกำลังทำการคัดลอกราคาแพง นี่เป็นเรื่องปกติหากคุณจำเป็นต้องใช้ค่าที่เพิ่มขึ้นล่วงหน้า แต่ถ้าไม่ทำเช่นนั้น postfix จะดีกว่ามาก ตัวอย่างจะเป็นตัววนซ้ำที่คุณมักใช้: for (pos = c.begin (); ... ; ++ pos) {} แทน pos ++
Eric

22
@ เอริก: คุณแก้ไขให้ถูกต้องตลอดนอกเหนือจากประโยคตรงกลางที่คุณผสม คำนำหน้าว่าดีกว่า
Martin York

6
เหตุใดจึงNumber operator++ (int)ใช้intเป็นพารามิเตอร์แม้ว่าคุณจะไม่ได้ใช้ก็ตาม
Sean Letendre

10
@SeanLetendre: มันไม่ได้ใช้พารามิเตอร์ int จริง มันเป็นพารามิเตอร์ปลอม แต่ผู้ออกแบบภาษา C ++ ต้องกำหนดวิธีแยกความแตกต่างระหว่างคำนำหน้าและคำจำกัดความของฟังก์ชัน postfix นี่คือการตัดสินใจออกแบบที่พวกเขาทำ
Martin York

2
@EnricoMariaDeAngelis: ไวยากรณ์แยกความแตกต่างของทั้งสอง ++xเป็นคำนำหน้าและเรียกoperator++() ในขณะที่x++เป็น postfix จึงโทรoperator++(int)
Martin York

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

คุณมีสองวิธีในการโอเวอร์โหลดตัวดำเนินการสองตัว (คำนำหน้า / postfix) ++ สำหรับประเภท 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 (ตราบใดที่อยู่ในเนมสเปซเดียวกัน)

มีข้อดีสองประการของสัญกรณ์ฟังก์ชันที่ไม่ใช่สมาชิก:

  • หากคุณจัดการเขียนโค้ดโดยไม่ทำให้พวกเขาเป็นเพื่อนกับ T คุณก็จะเพิ่มการห่อหุ้ม T
  • คุณสามารถใช้สิ่งนี้กับคลาสหรือโครงสร้างที่คุณไม่ได้เป็นเจ้าของรหัส นี่เป็นวิธีที่ไม่ล่วงล้ำเพื่อปรับปรุงอินเทอร์เฟซของวัตถุโดยไม่ต้องแก้ไขการประกาศ

1

ประกาศดังนี้:

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

};

นำไปใช้อย่างถูกต้อง - อย่ายุ่งกับสิ่งที่ทุกคนรู้ว่าพวกเขาทำ (เพิ่มแล้วใช้ใช้แล้วเพิ่มขึ้น)


-2

ฉันรู้ว่ามันสายไป แต่ฉันก็มีปัญหาเดียวกันและพบวิธีแก้ปัญหาที่ง่ายกว่า อย่าเข้าใจฉันผิดนี่เป็นวิธีแก้ปัญหาเดียวกับวิธีด้านบน (โพสต์โดย Martin York) มันง่ายกว่าเล็กน้อย แค่เล็กน้อย. นี่คือ:

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 ++ ควรส่งคืนค่าก่อนที่จะเพิ่มขึ้นไม่ใช่ตามหลัง
Kuilin Li

คำตอบนี้ไม่ถูกต้อง จำเป็นต้องใช้ชั่วคราว
Rian Quinn
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.