ทำไมฟังก์ชั่นเสมือนล้วนเริ่มต้นด้วย 0


147

เรามักจะประกาศฟังก์ชั่นเสมือนที่บริสุทธิ์เป็น:

virtual void fun () = 0 ;

นั่นคือมันถูกกำหนดเป็น 0 เสมอ

สิ่งที่ฉันเข้าใจคือนี่คือการเริ่มต้นรายการ vtable สำหรับฟังก์ชั่นนี้เป็นโมฆะและค่าอื่น ๆ ที่นี่ส่งผลให้เกิดข้อผิดพลาดในเวลารวบรวม ความเข้าใจนี้ถูกต้องหรือไม่?


12
โปรดทราบว่า vtable ไม่ใช่ข้อกำหนดทางภาษา แต่เป็นเพียงตัวเลือกการนำไปใช้สำหรับวิธีเสมือน คอมไพเลอร์สามารถสร้างสิ่งที่เป็นนามธรรมเดียวกันกับการใช้งานที่แตกต่างกัน (นั่นคือโดยไม่มี vtable และไม่มีองค์ประกอบใด ๆ ที่มี 0)
David Rodríguez - dribeas

@hype คำถามเสริมของคุณอีกครั้ง - นั่นคือสิ่งที่คำตอบของฉัน (และอื่น ๆ อีกมากมาย) พูดว่า

แค่อยากรู้อยากเห็นจะเกิดอะไรขึ้นถ้าฉันให้ virtual void func() = 100;
krithikaGopalakrisnan

คำตอบ:


161

เหตุผลที่=0ใช้คือ Bjarne Stroustrup ไม่คิดว่าเขาจะได้คำค้นหาอื่นเช่น "บริสุทธิ์" ผ่านชุมชน C ++ ในเวลาที่มีการใช้งานคุณลักษณะ อธิบายไว้ในหนังสือของเขาที่ชื่อThe Design & Evolution of C ++ตอนที่ 13.2.3

เลือกไวยากรณ์อยากรู้อยากเห็น = 0 แล้ว ... เนื่องจากในเวลานั้นฉันไม่เห็นโอกาสที่จะได้รับการยอมรับคำหลักใหม่

เขายังระบุอย่างชัดเจนด้วยว่าไม่จำเป็นต้องตั้งค่ารายการ vtable เป็น NULL และการทำเช่นนั้นไม่ใช่วิธีที่ดีที่สุดในการใช้งานฟังก์ชั่นเสมือนจริง


4
ใช่มันเป็นเพียงไวยากรณ์ ฉันเคยเห็นโครงการมากมายที่ #define PURE = 0 และพวกเขาจะพูดว่า void เสมือน Foo () PURE;
i_am_jorf

79
ได้โปรดพระเจ้าปกป้องฉันให้ห่างจากโครงการเหล่านั้น :-)

27
มันแย่กว่า #define BEGIN {#define END} ;-) มากและฉันเคยเห็นมาบ้างแล้ว
Toon Krijthe

5
สิ่งที่ดีแบบนี้ทำให้ฉันคิดว่า C ++ ไม่ได้ขัดมาก มันแปลกเพราะมันใช้งานเยอะมาก ฉันหวังว่าภาษาจะดีขึ้นเมื่อเวลาผ่านไป
jokoon

19
ดังนั้นในคำอื่น ๆ Bjarne คือ "ต้องเผชิญกับเส้นตาย" และ "ใช้แฮ็ค" เพื่อผ่าน "ข้อบกพร่องการออกแบบ";) (เพิ่งจะเป็นที่น่ากลัว)
Carl

78

เช่นเดียวกับคำถาม "ทำไม" มากที่สุดเกี่ยวกับการออกแบบของ C ++ สถานที่แรกที่ต้องดูคือการออกแบบและวิวัฒนาการของ C ++โดย Bjarne Stroustrup 1 :

=0เลือกไวยากรณ์ที่น่าสนใจมากกว่าทางเลือกที่ชัดเจนในการแนะนำคำหลักใหม่pureหรือ abstractเพราะในเวลานั้นฉันไม่เห็นโอกาสที่จะได้รับการยอมรับคำหลักใหม่ ถ้าฉันแนะนำpureRelease 2.0 จะจัดส่งโดยไม่มีคลาสนามธรรม ด้วยตัวเลือกระหว่างไวยากรณ์ที่ดีกว่ากับคลาสนามธรรมฉันเลือกคลาสนามธรรม แทนที่จะเสี่ยงต่อความล่าช้าและทำให้การต่อสู้เกิดขึ้น pureฉันใช้ประเพณีการประชุม C และ C ++ ของการใช้ 0 เพื่อแสดงว่า "ไม่อยู่ที่นั่น" =0พอดีไวยากรณ์กับมุมมองของฉันว่าร่างกายเป็นฟังก์ชั่นการเริ่มต้นสำหรับฟังก์ชั่นยังมี (แบบง่ายๆ แต่มักจะเพียงพอ) มุมมองของการตั้งค่าของฟังก์ชั่นเสมือนจริงที่ถูกนำมาใช้เป็นตัวชี้เวกเตอร์ของฟังก์ชั่น [... ]

1 §13.2.3ไวยากรณ์


29

ส่วนที่ 9.2 ของมาตรฐาน C ++ ให้ไวยากรณ์สำหรับสมาชิกคลาส มันรวมถึงการผลิตนี้:

pure-specifier:
    = 0

ไม่มีอะไรพิเศษเกี่ยวกับคุณค่า "= 0" เป็นเพียงไวยากรณ์ของการพูดว่า "ฟังก์ชันนี้เป็นเสมือนจริง" มันไม่เกี่ยวอะไรกับการเริ่มต้นหรือพอยน์เตอร์พอยน์เตอร์หรือค่าตัวเลขศูนย์ถึงแม้ว่าความคล้ายคลึงกับสิ่งเหล่านั้นอาจมีค่าช่วยในการจำ


5
+1 สำหรับการอ้างอิงถึงมาตรฐาน C ++ เป็นเรื่องที่น่าแปลกใจมากที่คำตอบที่ดีที่สุดข้อหนึ่งและได้รับเพียง 1 โหวต การอ่านมาตรฐานควรเป็นขั้นตอนแรกเพื่อแก้ไขคำถาม C ++
mloskot

7
@mloskot: อาจเป็นเพราะมันไม่ได้ตอบคำถามของ OP เพียงแค่เรียกคืนสถานการณ์หรือไม่
ใครบางคนเพียง

6
@ แค่ใครสักคน - มันรวมการอ้างอิงมาตรฐานซึ่งระบุว่าอะไรคือไวยากรณ์ของการประกาศฟังก์ชั่นเสมือนจริงและไวยากรณ์นั้นใช้ตัวระบุบริสุทธิ์ - = 0มีอะไรอีกที่คุณอยากรู้? มันจะเหมือนกับการถามว่าทำไมฟังก์ชัน body ห่อด้วย {} คำตอบจะเป็นเพราะนั่นคือสิ่งที่ไวยากรณ์ C ++ กำหนด
mloskot

19

ฉันไม่แน่ใจว่ามีความหมายใด ๆ ที่อยู่เบื้องหลังนี้หรือไม่ มันเป็นเพียงไวยากรณ์ของภาษา


16

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

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


3
+1 สำหรับการอธิบายข้อเสียของการแนะนำคำหลักใหม่ นั่นเป็นประโยชน์ในการเข้าใจเหตุผล แต่ไวยากรณ์ของ C ++ ดูเหมือนจะทำให้ฉันเข้าใจผิดและฉันหวังว่าพวกเขาจะทำให้คนอ่านได้ง่ายขึ้น - pureคำหลักคงจะดีมากในหนังสือของฉัน อย่างไรก็ตามมันเป็นเรื่องดีที่จะเข้าใจเหตุผล
Keith Pinson

@KeithPinson #define pure = 0หากคุณต้องการคำหลักที่บริสุทธิ์ที่คุณสามารถ
jdh8

@ jdh8: เอ่อ แค่ ... ฮึ
sbi

ในด้านของคลาส Bjarne เขาบอกว่าเขาต้องการได้คีย์เวิร์ด "pure" เป็น C ++ แต่เขาพยายามที่จะให้มันช้ามากในรอบก่อนที่คอมไพเลอร์ C ++ จะถูกจัดส่ง (IIRC น้อยกว่าสองสัปดาห์) เห็นได้ชัดว่ามันไม่ได้ทำให้มัน
ThePhD

@ThePhD: ISTR เขายังกล่าวถึงสิ่งนี้ใน D&E (ฉันขี้เกียจเกินกว่าที่จะค้นหาได้)
sbi

11

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


2
-0: เมื่อคุณไม่มีอะไรจะพูดด้วยตัวเองให้ใช้คำพูดที่ครอบคลุม (ดูคำตอบของ Jerry Coffin สำหรับ +1;)
ใครสักคน

7

ในกรณีนี้ไม่มี "initilaized" หรือ "มอบหมาย" เป็นศูนย์ = 0ในโครงสร้างการสร้างประโยคประกอบด้วย=และ0โทเค็นซึ่งไม่มีความเกี่ยวข้องกับการเริ่มต้นหรือการมอบหมาย

มันไม่มีความสัมพันธ์กับค่าจริงใด ๆ ใน "vtable" ภาษา C ++ ไม่มีความคิด "vtable" หรืออะไรทำนองนั้น "vtables" หลากหลายไม่มีอะไรมากไปกว่ารายละเอียดของการใช้งานเฉพาะ


3

ฉันจำได้ว่าการอ่านว่าเหตุผลสำหรับไวยากรณ์ที่ตลกคือมันง่ายกว่า (ในแง่ของการยอมรับมาตรฐาน) กว่าการแนะนำคำหลักอื่นที่จะทำในสิ่งเดียวกัน

ฉันเชื่อว่าสิ่งนี้ถูกกล่าวถึงในการออกแบบและวิวัฒนาการของ C ++ โดย Bjarne Stroustrup


2

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


2

= 0ประกาศฟังก์ชันเสมือนบริสุทธิ์

สิ่งที่เข้าใจคือสิ่งนี้คือการเริ่มต้นรายการ vtable สำหรับฟังก์ชั่นนี้ให้เป็นโมฆะและค่าอื่น ๆ ที่นี่ส่งผลให้เกิดข้อผิดพลาดในการรวบรวมเวลา

ฉันไม่คิดว่ามันเป็นเรื่องจริง มันเป็นเพียงไวยากรณ์พิเศษ vtable คือการนำไปปฏิบัติ ไม่มีใครบอกว่ารายการ vtable สำหรับสมาชิกที่บริสุทธิ์จะต้องเป็นศูนย์ในการก่อสร้าง (แม้ว่าคอมไพเลอร์ส่วนใหญ่จัดการกับ vtables ที่คล้ายกัน)


4
ที่จริงไม่จริง ไม่มีอะไรผิดปกติกับการให้คำจำกัดความสำหรับฟังก์ชั่นเสมือนจริง สิ่งเดียวที่= 0ทำได้คือทำให้ทั้งคลาสเป็นนามธรรมและห้ามการโทรเสมือนไปยังฟังก์ชันบริสุทธิ์ การโทรที่ไม่ใช่เสมือนยังคงสมบูรณ์แบบซึ่งก็คือเมื่อมีการใช้คำจำกัดความ (หากคุณระบุไว้)
AnT

เพียงแค่ดูที่เอาต์พุต godbolt ไม่มีที่ว่างให้คลุมเครือหรือเก็งกำไร ฉันจะดูตัวเองในภายหลัง
Lewis Kelsey

ดูเหมือนว่าจะแทนที่รายการด้วย__cxa_pure_virtual arobenko.gitbooks.io/bare_metal_cpp/content/compiler_output/แทนการใช้ Base :: f ()
Lewis Kelsey

1

นอกจากนี้คุณยังสามารถเริ่มต้นรายการ vtable เพื่อชี้ไปที่ฟังก์ชั่นที่เกิดขึ้นจริง "

 virtual void fun()
 {
     //dostuff()
 }

ดูเหมือนง่ายที่รายการ vtable สามารถกำหนดให้ชี้ไปที่ใดก็ได้ (0) หรือฟังก์ชัน ให้คุณระบุค่าของคุณเองสำหรับมันอาจส่งผลให้มันชี้ไปที่ขยะแทนที่จะไปที่ฟังก์ชั่น แต่นั่นคือเหตุผลที่อนุญาตให้ "= 0" และ "= 1" ไม่ได้ ฉันสงสัยว่า Neil Butterworth นั้นถูกต้องเกี่ยวกับสาเหตุที่ใช้ "= 0" เลย


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