ภาษา OO ใด ๆ สนับสนุนกลไกในการรับประกันวิธี overriden จะเรียกฐานหรือไม่


12

ฉันคิดว่านี่อาจเป็นคุณสมบัติภาษาที่มีประโยชน์และสงสัยว่ามีภาษาใดรองรับอยู่หรือไม่

ความคิดคือถ้าคุณมี:

class C
  virtual F
     statement1
     statement2

และ

class D inherits C
  override F
     statement1
     statement2
     C.F()

จะมีคำหลักที่ใช้กับ CF () ซึ่งการลบบรรทัดสุดท้ายของรหัสด้านบนจะทำให้เกิดข้อผิดพลาดของคอมไพเลอร์เพราะมันบอกว่า "วิธีนี้สามารถถูกแทนที่ได้ แต่การใช้งานที่นี่ต้องทำงานไม่ว่าอะไรก็ตาม"


คำตอบ:


14

ใช่. มันถูกเรียกว่าแบบจำลองสแกนดิเนเวียของ OO มันถูกใช้เช่นใน Simula (รูปแบบ OO อื่น ๆ ที่แพร่หลายและได้รับตามที่ได้รับในขณะนี้คือแบบจำลองอเมริกัน) ในแบบจำลองสแกนดิเนเวียคุณจะไม่เอาชนะ แต่ให้การทำงานย่อย

ในวิธีการของ Superclass foo:

some-code-before
INNER // this is the actual Simula keyword
some-code-after

ในเมธอดคลาสย่อย 'foo:

some-code-in-subclass

ถ้าคุณเรียกวิธี foo Superclass' กรณีเท่านั้นsome-code-beforeและsome-code-afterที่เกิดขึ้น ( INNERไม่ทำอะไรเลย) แต่ถ้าคุณโทร foo คลาสกรณีก็ไม่some-code-before, แล้วsome-code-in-subclasssome-code-after


9

ไม่มีภาษาที่ฉันรู้ว่ามีการบังคับให้เรียกวิธีการเขียนทับ แน่นอนว่าบางภาษาอนุญาตวิธีการแทนที่ที่ไม่สามารถเอาชนะได้ (เช่นการใช้newคำหลักใน C #) อย่างไรก็ตามมีสองวิธีในการเข้าใกล้สิ่งนี้

วิธีแรกคือสร้างเมธอด unoverridable (เช่นที่ไม่มีvirtualคีย์เวิร์ดใน C # หรืออันที่มีfinalคีย์เวิร์ดใน Java) ที่เรียกเมธอด overridable ที่ไม่สามารถเรียกได้จากนอกคลาส (เช่นprotectedใน C #, Java หรือ C ++)

class C
  A
     statement1
     F
     statement3

  protected virtual F
     statement2

และ

class D inherits C

  protected override F
     statement4
     C.F()

การแทนที่คลาสCนั้นมีอิสระที่จะแทนที่Fและปรับเปลี่ยนพฤติกรรม แต่ผู้โทรจากภายนอกคลาสเข้าถึงได้Aเท่านั้น

แก้ไข: ในฐานะที่เป็นคนอื่น ๆ ได้ออกมาชี้นี้เรียกว่ารูปแบบวิธีการแม่แบบ

วิธีที่สองคือการใช้ภาษาที่บังคับใช้เงื่อนไขและ postconditions ที่ระบุไว้ในคลาสฐานเช่นไอเฟลหรือ C # กับสัญญารหัส มันจะไม่บังคับให้คลาสฐานที่จะเรียก แต่วิธีการแทนที่สามารถถูกบังคับให้ทำงบเดียวกัน การใช้แง่มุมอาจช่วยได้หากภาษายอมให้มีการสืบทอดมุมมอง


2
คุณสามารถสร้างวิธีที่จะ overriden privateใน C ++ :) Herb Sutter อธิบายรายละเอียดได้ที่นี่
fredoverflow

รูปแบบเทมเพลตมีข้อเสียเพียงข้อเดียวที่คุณต้องนำมาใช้ใหม่ทุกครั้งในขณะที่ลึกผ่านลำดับชั้นการสืบทอด ตัวอย่างของ Simula นั้นดูสง่างามยิ่งขึ้นและยังคงมีรูปแบบเทมเพลต
Pavel Voronin

7

ไม่ได้เป็นส่วนหนึ่งของภาษาจริงๆ แต่เครื่องมือวิเคราะห์โค้ดแบบคงที่ FindBugs สำหรับ Java มีคำอธิบายประกอบOverrideMustInvokeที่นักพัฒนาสามารถเพิ่มไปยังวิธีการและจะทำให้ FindBugs แสดงข้อผิดพลาดหากพบวิธีการเอาชนะที่ไม่เรียกใช้ super . มันยังอนุญาตให้ระบุว่าการโทรจะต้องเป็นอันดับแรกหรือครั้งสุดท้ายในวิธีการเอาชนะ


6

กำหนดที่จะเรียกวิธี superclass คือการป้องกันรูปแบบ ถ้ามันไม่ได้ถูกบังคับใช้ในเวลารวบรวมมันเป็นข้อผิดพลาดง่ายซึ่งเป็นเหตุผลที่คุณกำลังมองหาโครงสร้างภาษาที่ตรวจสอบมัน

: มีวิธีการที่ได้รับการสนับสนุนในภาษา OO ทั้งหมดเป็นรูปแบบวิธีการแม่แบบ ที่นี่คุณสร้างเมธอดซูเปอร์คลาสที่ไม่ overridable และคุณเรียกเมธอด overridable คลาสย่อยนั้นสามารถแทนที่วิธีนี้เพื่อเพิ่มฟังก์ชันการทำงาน:

class super {
  public final void doSomething() {
    doSpecialthing();
    doMore();
  }
  public void doSpecialthing() {
  }
}

ขึ้นอยู่กับตำแหน่งของการเรียกไปยังเมธอด overridden มันยังอนุญาตให้กำหนดลำดับของการดำเนินการซึ่งด้วย super call สามัญจะเป็นไปตามความประสงค์ของ subclass implementer


1

รูปแบบที่ใกล้เคียงที่สุดที่ฉันนึกได้คือเหตุการณ์ที่สมัครเป็นสมาชิกด้วยตนเอง มันค่อนข้างยุ่งยากและไม่ง่ายเลยสำหรับ coder แต่บรรลุเป้าหมาย

class C
{
    public void F()
    {
        ...
        OnF()
    }

    protected event OnF
}

class D : C
{
    public D()
    {
        base.OnF += this.F
    }

    private void F
    {
        ...
    }
}

1
นี่เป็นรูปแบบการออกแบบที่ใช้กันทั่วไปบางครั้งมีทั้งการเขียนทับแบบมืออาชีพและโพสต์ ViewWillAppear (), ViewDidAppear () เหมาะอย่างยิ่งเมื่อคุณต้องการที่จะอนุญาตให้ subclasses ที่จะขยาย (แทนที่จะแก้ไข) พฤติกรรมเริ่มต้น
Kris Van Bael

1

เครื่องเสียงกระเพื่อม "รส" อนุญาตวิธีการที่มีประเภท "ก่อน" "หลัง" และ "รอบ" วิธีการหลักที่สืบทอดมา


0

Dในขณะที่ไม่ได้เป็นความคิดที่ดีในทางทฤษฎีมันจะมีในเชิงลบผลข้างเคียงของการฝืนตัวเลือกของฉันเมื่อการดำเนินการ ตัวอย่างเช่นจะเกิดอะไรขึ้น (ด้วยเหตุผลที่ไม่อาจหยั่งรู้ได้) จะสะดวกกว่าที่จะเรียกใช้งานซูเปอร์คลาสของFจากวิธีอื่น:

class D inherits C
    override F
        statement1
        statement2
        G()
    G
        statement3
        C.F()
        statement4

ภายใต้สถานการณ์ของคุณผมคิดว่าคอมไพเลอร์จะธงการดำเนินการFในDแม้ว่ามันจะไม่ (อ้อม) C.F()โทร

โดยทั่วไปสิ่งที่คุณอธิบายไว้เป็นกลไกที่เป็นไปได้ที่จะช่วยให้คอมไพเลอร์รับรู้เมื่อมีการCละเมิดสัญญาที่สืบทอดมาจากคลาส ประเด็นของฉันคือว่าในขณะที่เป็นสิ่งที่ดีมันไม่ควรมีค่าใช้จ่ายในการ จำกัดวิธีที่ฉันสามารถใช้คลาสย่อยของฉัน


1
-1: ความสามารถในการคิดถึงสถานการณ์ที่คุณไม่ต้องการใช้นั่นไม่ใช่คำตอบสำหรับคำถามที่ว่า "ภาษาใดที่อนุญาตให้ทำได้"

@ GrahamLee: จริงมาก ประเด็นของฉันคือพยายามอธิบายเหตุผลหนึ่งว่าทำไมไม่มีภาษา (ที่ฉันรู้) ใช้คุณลักษณะเช่นนั้น ฉันเดาว่าฉันถูกจับได้ว่าอธิบายว่าทำไมฉันถึงอธิบายว่าทำไมฉันถึงอธิบาย -1 ได้รับการยอมรับอย่างมีความสุข :)
Mac
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.