คำหลัก 'แทนที่' เป็นเพียงการตรวจสอบวิธีเสมือนจริงที่ถูกแทนที่หรือไม่


226

เท่าที่ฉันเข้าใจการแนะนำของoverrideคำหลักใน C ++ 11 ไม่มีอะไรมากไปกว่าการตรวจสอบเพื่อให้แน่ใจว่าฟังก์ชั่นการใช้งานเป็นการนำoverrideของvirtualฟังก์ชั่นในชั้นฐาน

มันคืออะไร


50
ใช่
.

13
มันไม่ใช่การตรวจสอบอีกครั้ง มันเป็นเพียงการตรวจสอบ
Nikos C.

13
เฮ้การแทนที่ไม่ใช่คำหลักมันเป็นไวยากรณ์น้ำตาล int override = 42; // OK
KAlO2

2
นอกจากนี้ยังช่วยปรับปรุงความสามารถในการอ่านการอธิบายฟังก์ชั่นที่ประกาศถูกแทนที่ด้วย)
mots_g

5
ดังนั้นเอ่อ ... C ++ 11 จะกลายเป็นมาตรฐานมากพอที่พวกเขาจะเริ่มสอนสิ่งนี้ในท้องถิ่นของฉัน 4 ปี พวกเขาจะรู้เมื่อไหร่!
Cinch

คำตอบ:


263

นั่นเป็นความคิดที่แน่นอน ประเด็นก็คือคุณมีความชัดเจนเกี่ยวกับสิ่งที่คุณหมายถึงเพื่อให้สามารถวินิจฉัยข้อผิดพลาดแบบเงียบได้:

struct Base
{
    virtual int foo() const;
};

struct Derived : Base
{
    virtual int foo()   // whoops!
    {
       // ...
    }
};

โค้ดข้างต้นรวบรวม แต่ไม่ใช่สิ่งที่คุณอาจหมายถึง (หมายเหตุที่ขาดหายไปconst) หากคุณพูดแทนคุณvirtual int foo() overrideจะได้รับข้อผิดพลาดของคอมไพเลอร์ซึ่งฟังก์ชั่นของคุณไม่ได้อยู่เหนือความจริง


74
+1: แต่น่าเสียดายที่มันเป็นปลาเฮอริ่งแดงเมื่อมีคนแนะนำว่าoverrideคุณสมบัติใหม่นี้ "แก้ไข" สิ่งนี้; คุณต้องจำไว้ว่าให้ใช้มันอย่างที่ควรจำไว้เพื่อเขียนconst;)
Lightness Races ใน Orbit

ฉันเพิ่งรู้explicitคำจำกัดความของคลาสไม่ได้ทำให้เป็น C ++ 11 ฮะ.
aschepler

1
@aschepler แล้วexplicitนิยามของคลาสจะทำอย่างไร ไม่เคยได้ยินเรื่องนี้เลย
Christian Rau

18
@LightnessRacesinOrbit: ใช่มันไม่ได้โง่พิสูจน์; แต่ความทรงจำที่เป็นกฎทั่วไป (จากการเขียนอย่างบ้าคลั่งoverrideเมื่อหนึ่งความตั้งใจที่จะทำมัน) คือจะมีโอกาสมากกว่าการจดจำกรณีมุมเช่นมีทั่วไปในการคัดลอกการทำงานของต้นแบบที่แตกต่างกันเพียงความผิดปกติเหมือนหายไปไม่มีconstหรือเขียนcharแทนintฯลฯ
legends2k

1
@Light overrideกล่าวถึงกรณีการใช้ตัวระบุที่ดีที่สุดในคำตอบนี้ซึ่งเป็นอนาคตมากกว่าในทันที คำตอบแนะนำว่าให้overrideใช้virtualวิธีการต่อไป ในอนาคตเมื่อมีการเปลี่ยนแปลงลายเซ็นผิดพลาดความมีประโยชน์จะเริ่มทำงาน
iammilind

35

คำพูดของ Wikipedia:

การแทนที่ตัวระบุพิเศษหมายความว่าคอมไพเลอร์จะตรวจสอบคลาสฐาน (es) เพื่อดูว่ามีฟังก์ชั่นเสมือนจริงที่มีลายเซ็นที่แน่นอนนี้ และหากไม่มีตัวแปลภาษาก็จะผิดพลาด

http://en.wikipedia.org/wiki/C%2B%2B11#Explicit_overrides_and_final

แก้ไข (พยายามปรับปรุงคำตอบเล็กน้อย):

การประกาศเมธอดเป็น "override" หมายความว่าเมธอดนั้นมีจุดประสงค์เพื่อเขียนเมธอด (เสมือน) บนคลาสพื้นฐาน วิธีการเอาชนะต้องมีลายเซ็นเดียวกัน (อย่างน้อยสำหรับพารามิเตอร์อินพุต) เป็นวิธีที่มันตั้งใจที่จะเขียนใหม่

ทำไมถึงจำเป็น กรณีข้อผิดพลาดทั่วไปสองกรณีต่อไปนี้ได้รับการป้องกัน:

  1. หนึ่งพิมพ์ผิดในวิธีการใหม่ คอมไพเลอร์ไม่ทราบว่ามีความตั้งใจที่จะเขียนวิธีการก่อนหน้าเพียงแค่เพิ่มวิธีนี้ลงในคลาสเป็นวิธีการใหม่ ปัญหาคือว่าวิธีการเดิมยังคงอยู่ที่นั่นวิธีการใหม่จะถูกเพิ่มเป็นโอเวอร์โหลด ในกรณีนี้การเรียกไปยังเมธอดเก่าทั้งหมดจะทำงานเหมือนเมื่อก่อนโดยไม่มีการเปลี่ยนแปลงในพฤติกรรม (ซึ่งจะเป็นจุดประสงค์ของการเขียนใหม่)

  2. หนึ่งลืมที่จะประกาศวิธีการในซูเปอร์คลาสเป็น "เสมือน" แต่ยังคงพยายามที่จะเขียนมันใหม่ในคลาสย่อย ในขณะที่สิ่งนี้จะได้รับการยอมรับพฤติกรรมจะไม่ตรงตามที่ตั้งใจไว้: วิธีการนี้ไม่ได้เป็นเสมือนจริงดังนั้นการเข้าถึงผ่านพอยน์เตอร์ไปยังซูเปอร์คลาสจะสิ้นสุดการเรียกเมธอดเก่า (superclass ') แทนวิธีการใหม่

การเพิ่ม "การแทนที่" อย่างชัดเจนทำให้ disambiguates สิ่งนี้: ผ่านสิ่งนี้สิ่งหนึ่งกำลังบอกคอมไพเลอร์ว่ามีสามสิ่งที่คาดหวัง:

  1. มีวิธีการที่มีชื่อเดียวกันในซูเปอร์คลาส
  2. วิธีการนี้ในซุปเปอร์คลาสนั้นถูกประกาศเป็น "เสมือน" (นั่นหมายถึงตั้งใจจะเขียนใหม่)
  3. วิธีใน superclass มีลายเซ็น (input *) เดียวกันกับวิธีใน subclass (วิธีการเขียนใหม่)

หากสิ่งเหล่านี้เป็นเท็จแสดงว่ามีข้อผิดพลาด

* หมายเหตุ: บางครั้งพารามิเตอร์เอาท์พุทจะแตกต่างกัน แต่เป็นประเภทที่เกี่ยวข้อง อ่านเกี่ยวกับการแปรปรวนร่วมและการแปรเปลี่ยนหากสนใจ


31

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


1
+1 แม้ว่าในขณะที่overrideเป็นวิธีที่ดีในการค้นพบปัญหาดังกล่าวหน่วยทดสอบครอบคลุมที่ดีก็ควรช่วย
ไม่แยแส

1
นั่นเป็นเหตุผลว่าทำไมฉันถึงตื่นเต้นกับตัวระบุใหม่ ปัญหาเดียวก็คือว่าคุณสมบัตินี้จะต้องมีอยู่แล้วเพื่อป้องกันข้อผิดพลาดที่เกิดจากการเปลี่ยนแปลงในชั้นฐาน ;-)
Wolf

5

ใช่มันเป็นเช่นนั้น เป็นการตรวจสอบเพื่อให้แน่ใจว่าไม่ได้ลองแทนที่และทำมันผ่านลายเซ็นที่เรียบร้อย นี่คือหน้าวิกิที่อธิบายรายละเอียดนี้และมีตัวอย่างสั้น ๆ :

http://en.wikipedia.org/wiki/C%2B%2B11#Explicit_overrides_and_final


2

ร่างมาตรฐาน C ++ 17

หลังจากไปดูoverrideเพลงฮิตทั้งหมดในร่างมาตรฐาน C ++ 17 N4659การอ้างอิงเดียวที่ฉันสามารถหาoverrideตัวระบุได้คือ:

5 หากฟังก์ชันเสมือนถูกทำเครื่องหมายด้วยการแทนที่ virt-specifier และไม่แทนที่ฟังก์ชันสมาชิกของคลาสพื้นฐานโปรแกรมจะถูกจัดรูปแบบไม่ถูกต้อง [ตัวอย่าง:

struct B {
  virtual void f(int);
};

struct D : B {
  virtual void f(long) override; // error: wrong signature overriding B::f
  virtual void f(int) override;  // OK
}

- ตัวอย่างท้าย]

ดังนั้นฉันคิดว่าการระเบิดโปรแกรมที่ไม่ถูกต้องอาจเป็นผลกระทบเดียว

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