เป็นการดีที่จะวางคำจำกัดความ C ++ ลงในไฟล์ส่วนหัวหรือไม่?


196

สไตล์ส่วนตัวของฉันกับ C ++ มีเสมอที่จะนำการประกาศชั้นในรวมไฟล์และคำนิยามในแฟ้ม .cpp เป็นอย่างมากเช่นที่ระบุไว้ในคำตอบของโลกิจะc ++ หัวไฟล์แยกรหัส ส่วนหนึ่งของเหตุผลที่ฉันชอบสไตล์นี้น่าจะเกี่ยวข้องกับหลายปีที่ฉันใช้การเข้ารหัส Modula-2 และ Ada ซึ่งทั้งสองแบบมีรูปแบบคล้ายกันกับไฟล์ข้อมูลจำเพาะและไฟล์เนื้อหา

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

ฉันไม่ได้งอเหมือนที่เคยเป็นดังนั้นฉันจึงไม่กังวลที่จะเข้าหา bandwagon ของเขาจนกว่าฉันจะเห็นคนอีกไม่กี่คนอยู่ข้างๆเขา ดังนั้นสำนวนนี้เป็นเรื่องธรรมดามากจริง ๆ ?

เพียงเพื่อให้โครงสร้างบางอย่างเพื่อตอบ: ตอนนี้มันเป็นวิธีที่พบมากค่อนข้างทั่วไปเรื่องผิดปกติหรือข้อผิดพลาดออกบ้า?


ฟังก์ชั่นหนึ่งบรรทัด (getters และ setters) ในส่วนหัวเป็นเรื่องปกติ นานกว่าที่จะได้รับภาพรวมวินาทีที่แปลกประหลาด บางทีสำหรับคำจำกัดความที่สมบูรณ์ของคลาสเล็ก ๆ ที่ถูกใช้โดยอีกอันในหัวข้อเดียวกัน?
มาร์ติน Beckett

ฉันใส่คำจำกัดความของชั้นเรียนไว้ในส่วนหัวเสมอ คำจำกัดความเฉพาะสำหรับคลาส pimpl เป็นข้อยกเว้น ฉันประกาศเฉพาะในส่วนหัว
Johannes Schaub - litb

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

4
@ WKS - Microsoft ต้องการให้ทุกคนโปรแกรมใน C # และใน C # ไม่มีความแตกต่างของ "header" vs "body" มันเป็นเพียงไฟล์เดียว เมื่ออยู่ในโลกทั้ง C ++ และ C # มาเป็นเวลานานทาง C # จึงง่ายต่อการจัดการ
Mark Lakata

1
@ MarkLakata - นั่นเป็นหนึ่งในสิ่งที่เขาชี้ไป ฉันไม่เคยได้ยินเรื่องนี้จากเขามาก่อน แต่ IIRC เขาโต้เถียงว่า Java และ C # ทำงานในลักษณะนี้และ C # เป็นแบรนด์ใหม่ในเวลานั้นซึ่งทำให้เป็นแนวโน้มที่ภาษาทั้งหมดจะตามมาในไม่ช้า
TED

คำตอบ:


209

ผู้ร่วมงานของคุณผิดวิธีที่พบบ่อยคือการใส่รหัสในไฟล์. cpp (หรือนามสกุลที่คุณต้องการ) และการประกาศในส่วนหัว

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

ในที่สุดมันก็มักจะน่ารำคาญที่มีความสัมพันธ์วัตถุวงกลม (บางครั้งต้องการ) เมื่อรหัสทั้งหมดเป็นส่วนหัว

บรรทัดล่างคุณพูดถูกเขาผิด

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

แก้ไข:บางคนต้องการชี้แจงเพิ่มเติมเล็กน้อยต่อไปนี้เป็นความคิดบางอย่างเกี่ยวกับข้อเสียในการเขียนรหัส "ส่วนหัวเท่านั้น":

หากคุณค้นหารอบ ๆ คุณจะเห็นผู้คนจำนวนมากพยายามหาวิธีลดเวลารวบรวมเมื่อจัดการกับการเพิ่มประสิทธิภาพ ตัวอย่างเช่น: วิธีลดเวลาในการรวบรวมด้วย Boost Asioซึ่งจะเห็นการรวบรวม 14 วินาทีของไฟล์ 1K ไฟล์เดียวที่มีการรวมไว้ด้วย ดูเหมือนว่ายุค 14 อาจจะไม่ใช่ "การระเบิด" แต่แน่นอนว่ามันนานกว่าปกติและสามารถรวมกันได้อย่างรวดเร็ว เมื่อต้องรับมือกับโครงการขนาดใหญ่ ส่วนหัวของไลบรารีเท่านั้นที่มีผลต่อเวลาในการรวบรวมในลักษณะที่วัดได้ค่อนข้าง เราเพียงแค่ทนเพราะการเพิ่มประสิทธิภาพนั้นมีประโยชน์มาก

นอกจากนี้ยังมีหลายสิ่งที่ไม่สามารถทำได้ในส่วนหัวเท่านั้น (แม้บูสต์จะมีไลบรารีที่คุณต้องการเชื่อมโยงไปยังบางส่วนเช่นเธรดระบบไฟล์ ฯลฯ ) ตัวอย่างหลักคือคุณไม่สามารถมีวัตถุโกลบอลอย่างง่ายในส่วนหัวเท่านั้น libs (เว้นแต่คุณจะหันไปใช้สิ่งที่น่ารังเกียจที่เป็นซิงเกิลตัน) เนื่องจากคุณจะพบข้อผิดพลาดหลาย ๆ ข้อกำหนด หมายเหตุ:ตัวแปรอินไลน์ของ C ++ 17 จะทำให้ตัวอย่างนี้เป็นไปได้ในอนาคต

เป็นจุดสุดท้ายเมื่อใช้เพิ่มเป็นตัวอย่างของรหัสส่วนหัวเท่านั้นรายละเอียดมากมักจะพลาด

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


16
ฉันค่อนข้างแน่ใจว่านั่นคือสิ่งที่เขาได้รับมา เมื่อใดก็ตามที่สิ่งนี้เกิดขึ้นเขาก็จะเปิดแม่แบบขึ้นมา ข้อโต้แย้งของเขาคร่าว ๆ ว่าคุณควรทำโค้ดทั้งหมดด้วยวิธีนี้เพื่อความมั่นคง
TED

14
ที่เป็นข้อโต้แย้งที่ไม่ดีเขาทำให้ติดปืนของคุณ :)
Evan Teran

11
นิยามเทมเพลตสามารถอยู่ในไฟล์ CPP ได้หากรองรับคำหลัก "ส่งออก" นั่นคือมุมมืดของ C ++ ที่โดยปกติแล้วจะไม่ได้ใช้งานโดยคอมไพล์ส่วนใหญ่เพื่อความรู้ที่ดีที่สุด
Andrei Taranchenko

2
ดูที่ด้านล่างของคำตอบนี้ (ด้านบนค่อนข้างซับซ้อน) ตัวอย่างเช่น: stackoverflow.com/questions/555330/…
Evan Teran

3
มันเริ่มมีความหมายต่อการสนทนานี้ที่ "ไชโยไม่มีตัวเชื่อมโยงผิดพลาด"
Evan Teran

158

วันที่ผู้เขียนรหัส C ++ เห็นด้วยกับทางแกะจะนอนกับสิงโตชาวปาเลสไตน์จะโอบกอดอิสราเอลและแมวและสุนัขจะได้รับอนุญาตให้แต่งงาน

การแยกระหว่างไฟล์. h และ. cpp นั้นส่วนใหญ่เป็นการกำหนดเอง ณ จุดนี้ซึ่งเป็นร่องรอยของการเพิ่มประสิทธิภาพคอมไพเลอร์ที่ผ่านมานาน ในสายตาของฉันประกาศอยู่ในส่วนหัวและคำจำกัดความที่อยู่ในไฟล์การใช้งาน แต่นั่นเป็นเพียงนิสัยไม่ใช่ศาสนา


140
"วันที่ C ++ coders เห็นด้วยกับวิธี ... " จะเหลือ coder เพียงหนึ่งเดียวเท่านั้น!
Brian Ensink

9
ฉันคิดว่าพวกเขาเห็นด้วยกับวิธีการประกาศใน. h และคำจำกัดความใน. cpp
hasen

6
เราทุกคนตาบอดและ C ++ เป็นช้าง
Roderick Taylor

นิสัย? ดังนั้นสิ่งที่เกี่ยวกับการใช้. h เพื่อกำหนดขอบเขต? มันถูกแทนที่ด้วยสิ่งใด?
Hernán Eche

28

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

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


1
"มันบังคับให้คอมไพล์ไฟล์ทั้งหมดใหม่ที่มีส่วนหัวเมื่อคุณเปลี่ยนรหัสจริงมากกว่าการประกาศ" ฉันคิดว่านี่เป็นเหตุผลที่แท้จริงที่สุด ยังไปกับข้อเท็จจริงที่ว่าการประกาศในส่วนหัวเปลี่ยนน้อยกว่าการใช้งานในไฟล์. c
Ninad

20

สิ่งที่อาจแจ้งให้คุณทราบถึงผู้ร่วมงานคือความคิดที่ว่ารหัส C ++ ส่วนใหญ่ควรเป็นเทมเพลตเพื่อให้สามารถใช้งานได้สูงสุด และถ้ามันเป็นเทมเพลตทุกอย่างจะต้องอยู่ในไฟล์ส่วนหัวเพื่อให้รหัสไคลเอนต์สามารถเห็นและยกตัวอย่างได้ ถ้ามันดีพอสำหรับ Boost และ STL มันก็ดีสำหรับเรา

ฉันไม่เห็นด้วยกับมุมมองนี้ แต่อาจเป็นที่มาของ


ฉันคิดว่าคุณพูดถูก เมื่อเราพูดถึงมันเขามักจะใช้ตัวอย่างของแม่แบบที่คุณต้องทำมากขึ้นหรือน้อยลง ฉันไม่เห็นด้วยกับ "ต้อง" เช่นกัน แต่ทางเลือกของฉันค่อนข้างซับซ้อน
TED

1
@ted - สำหรับโค้ดเทมเพลตคุณต้องนำการติดตั้งไปใช้ในส่วนหัว คำหลัก 'ส่งออก' อนุญาตให้คอมไพเลอร์สนับสนุนการแยกการประกาศและคำจำกัดความของแม่แบบ แต่การสนับสนุนเพื่อการส่งออกนั้นไม่มีอยู่จริง anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1426.pdf
Michael Burr

หัวใช่ แต่มันไม่ได้จะต้องมีส่วนหัวเหมือนกัน ดูคำตอบที่ไม่รู้จักด้านล่าง
TED

มันสมเหตุสมผล แต่ฉันไม่สามารถพูดได้ว่าฉันเคยเจอสไตล์นั้นมาก่อน
ไมเคิลเสี้ยน

14

ฉันคิดว่าเพื่อนร่วมงานของคุณฉลาดและคุณก็ถูกต้อง

สิ่งที่มีประโยชน์ที่ฉันพบว่าการใส่ทุกอย่างไว้ในส่วนหัวคือ:

  1. ไม่จำเป็นต้องเขียนและซิงค์ส่วนหัวและแหล่งข้อมูล

  2. โครงสร้างเป็นแบบธรรมดาและไม่มีการพึ่งพาแบบวงกลมบังคับให้ coder สร้างโครงสร้าง "ดีกว่า"

  3. พกพาง่ายต่อการฝังลงในโครงการใหม่

ฉันเห็นด้วยกับปัญหาเวลารวบรวม แต่ฉันคิดว่าเราควรสังเกตว่า:

  1. การเปลี่ยนแปลงของไฟล์ต้นฉบับมีแนวโน้มที่จะเปลี่ยนไฟล์ส่วนหัวซึ่งนำไปสู่โครงการทั้งหมดจะถูกคอมไพล์ใหม่อีกครั้ง

  2. ความเร็วในการรวบรวมนั้นเร็วกว่าเมื่อก่อนมาก และถ้าคุณมีโครงการที่จะสร้างด้วยเวลานานและความถี่สูงก็อาจบ่งบอกว่าการออกแบบโครงการของคุณมีข้อบกพร่อง แยกงานออกเป็นหลาย ๆ โครงการและโมดูลสามารถหลีกเลี่ยงปัญหานี้ได้

สุดท้ายฉันแค่ต้องการสนับสนุนเพื่อนร่วมงานของคุณในมุมมองส่วนตัวของฉัน


3
+1 ไม่มีใคร แต่คุณมีความคิดว่าในส่วนหัวของโปรเจ็กต์ที่ต้องใช้เวลาในการคอมไพล์นานอาจบ่งบอกถึงการพึ่งพามากเกินไปซึ่งเป็นการออกแบบที่ไม่ดี จุดดี! แต่การอ้างอิงเหล่านี้จะถูกลบออกไปจนถึงเวลาที่การรวบรวมสั้นหรือไม่?
TobiMcNamobi

@TobiMcNamobi: ฉันชอบความคิดของ "slacking" เพื่อรับข้อเสนอแนะที่ดีขึ้นเกี่ยวกับการตัดสินใจออกแบบที่ไม่ดี อย่างไรก็ตามในกรณีของการรวมส่วนหัวอย่างเดียวกับการคอมไพล์แยกต่างหากหากเราตัดสินด้วยความคิดนั้นเราก็จบลงด้วยการรวบรวมหน่วยเดียวและเวลาการคอมไพล์ครั้งใหญ่ แม้ในขณะที่การออกแบบนั้นยอดเยี่ยมจริงๆ
โจดังนั้น

กล่าวอีกนัยหนึ่งการแยกระหว่างอินเทอร์เฟซและการใช้งานนั้นเป็นส่วนหนึ่งของการออกแบบของคุณ ใน C คุณจะต้องแสดงการตัดสินใจของคุณเกี่ยวกับการห่อหุ้มผ่านการแยกส่วนหัวและการนำไปใช้
โจดังนั้น

1
ฉันเริ่มสงสัยว่ามีข้อเสียใด ๆ ที่จะเพียงแค่วางส่วนหัวเหมือนภาษาที่ทันสมัยทำ
โจดังนั้น

12

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

จำเอาไว้: ความสอดคล้องโง่หลอกเด็กของจิตใจของเล็ก ๆ น้อย ๆ


ใช่ฉันก็ทำเช่นนั้น กฎทั่วไปที่ฉันใช้ดูเหมือนจะเป็นบางสิ่งบางอย่างตามเส้นของ "ถ้ามันเหมาะกับรหัสหนึ่งบรรทัดทิ้งไว้ในส่วนหัว"
TED

จะเกิดอะไรขึ้นเมื่อไลบรารีจัดเตรียมเนื้อหาของคลาสเทมเพลตA<B>ในไฟล์ cpp แล้วผู้ใช้ต้องการA<C>หรือไม่
jww

@ jww ฉันไม่ได้ระบุอย่างชัดเจน แต่คลาสเทมเพลตควรมีการกำหนดไว้อย่างครบถ้วนในส่วนหัวเพื่อให้คอมไพเลอร์สามารถสร้างอินสแตนซ์ของมันได้ทุกประเภทที่ต้องการ นั่นเป็นข้อกำหนดทางเทคนิคไม่ใช่ตัวเลือกโวหาร ฉันคิดว่าปัญหาในคำถามเดิมคือมีคนตัดสินใจว่ามันดีสำหรับเทมเพลตหรือไม่มันก็ดีสำหรับคลาสปกติด้วย
Mark Ransom

7

ดังที่ Tuomas กล่าวว่าส่วนหัวของคุณควรน้อยที่สุด จะแล้วเสร็จฉันจะขยายตัวเล็กน้อย

ฉันเองใช้ไฟล์ 4 ประเภทในC++โครงการของฉัน:

  • สาธารณะ:
  • การส่งต่อส่วนหัว: ในกรณีของแม่แบบ ฯลฯ ไฟล์นี้จะได้รับการประกาศการส่งต่อที่จะปรากฏในส่วนหัว
  • ส่วนหัว: ไฟล์นี้มีส่วนหัวการส่งต่อหากมีและประกาศทุกสิ่งที่ฉันต้องการให้เป็นแบบสาธารณะ (และกำหนดคลาส ... )
  • เอกชน:
  • ไพรเวตส่วนหัว: ไฟล์นี้เป็นส่วนหัวที่สงวนไว้สำหรับการนำไปใช้งานรวมถึงส่วนหัวและประกาศฟังก์ชัน / โครงสร้างตัวช่วย (สำหรับ Pimpl ตัวอย่างหรือเพรดิเคต) ข้ามหากไม่จำเป็น
  • ไฟล์ต้นฉบับ: มันมีส่วนหัวส่วนตัว (หรือส่วนหัวหากไม่มีส่วนหัวส่วนตัว) และกำหนดทุกอย่าง (ไม่ใช่เทมเพลต ... )

นอกจากนี้ฉันจับคู่กับกฎอื่น: อย่ากำหนดสิ่งที่คุณสามารถส่งต่อประกาศ แม้ว่าแน่นอนฉันมีเหตุผล (ใช้ Pimpl ทุกที่ค่อนข้างยุ่งยาก)

หมายความว่าฉันต้องการประกาศล่วงหน้ามากกว่า #includeคำสั่งในส่วนหัวของฉันเมื่อใดก็ตามที่ฉันสามารถไปกับพวกเขา

ในที่สุดฉันก็ใช้กฎการมองเห็นด้วย: ฉัน จำกัด ขอบเขตของสัญลักษณ์ของฉันให้มากที่สุดเท่าที่จะทำได้เพื่อที่พวกเขาจะไม่สร้างมลภาวะให้กับขอบเขตภายนอก

นำมารวมกัน:

// example_fwd.hpp
// Here necessary to forward declare the template class,
// you don't want people to declare them in case you wish to add
// another template symbol (with a default) later on
class MyClass;
template <class T> class MyClassT;

// example.hpp
#include "project/example_fwd.hpp"

// Those can't really be skipped
#include <string>
#include <vector>

#include "project/pimpl.hpp"

// Those can be forward declared easily
#include "project/foo_fwd.hpp"

namespace project { class Bar; }

namespace project
{
  class MyClass
  {
  public:
    struct Color // Limiting scope of enum
    {
      enum type { Red, Orange, Green };
    };
    typedef Color::type Color_t;

  public:
    MyClass(); // because of pimpl, I need to define the constructor

  private:
    struct Impl;
    pimpl<Impl> mImpl; // I won't describe pimpl here :p
  };

  template <class T> class MyClassT: public MyClass {};
} // namespace project

// example_impl.hpp (not visible to clients)
#include "project/example.hpp"
#include "project/bar.hpp"

template <class T> void check(MyClass<T> const& c) { }

// example.cpp
#include "example_impl.hpp"

// MyClass definition

ผู้ช่วยชีวิตที่นี่คือส่วนใหญ่เวลาส่วนหัวไปข้างหน้าไร้ประโยชน์: จำเป็นเฉพาะในกรณีที่typedefหรือtemplateเป็นเช่นนั้นส่วนหัวการใช้งาน;)


6

หากต้องการเพิ่มความสนุกสนานมากขึ้นคุณสามารถเพิ่ม.ippไฟล์ที่มีการใช้งานเทมเพลต (ซึ่งรวมอยู่ใน.hpp) ในขณะที่.hppมีอินเทอร์เฟซ

นอกเหนือจากรหัส templatized (ขึ้นอยู่กับโครงการนี้อาจเป็นไฟล์ส่วนใหญ่หรือส่วนน้อย) มีรหัสปกติและที่นี่จะเป็นการดีกว่าที่จะแยกการประกาศและคำจำกัดความ จัดเตรียมการประกาศล่วงหน้าหากจำเป็น - ซึ่งอาจมีผลต่อเวลาการรวบรวม


นั่นคือสิ่งที่ฉันทำกับคำจำกัดความของเทมเพลตด้วย (แม้ว่าฉันไม่แน่ใจว่าฉันใช้ส่วนขยายเดียวกัน ... มันใช้เวลาสักครู่)
TED

5

โดยทั่วไปเมื่อเขียนคลาสใหม่ฉันจะใส่รหัสทั้งหมดลงในคลาสดังนั้นฉันไม่ต้องมองหาไฟล์อื่นสำหรับมัน .. หลังจากทุกอย่างทำงานได้ฉันแบ่งเนื้อหาของเมธอดออกเป็นไฟล์ cpp ออกจากต้นแบบในไฟล์ hpp


4

หากวิธีการใหม่นี้เป็นจริงวิธีที่เราอาจจะได้รับการทำงานในทิศทางที่แตกต่างกันในโครงการของเรา

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

นอกจากนี้เรายังใช้"ตัวชี้ทึบแสง" - รูปแบบเมื่อใช้ได้

ด้วยวิธีปฏิบัติเหล่านี้เราสามารถสร้างได้เร็วกว่าเพื่อนส่วนใหญ่ของเรา และใช่ ... การเปลี่ยนรหัสหรือสมาชิกคลาสจะไม่ทำให้เกิดการสร้างใหม่ขนาดใหญ่


4

ฉันทำสิ่งนี้เป็นการส่วนตัวในไฟล์ส่วนหัวของฉัน:

// class-declaration

// inline-method-declarations

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

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

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


2

IMHO เขามีบุญเท่านั้นถ้าเขาทำแม่แบบและ / หรือเมตาโปรแกรม มีเหตุผลมากมายที่กล่าวถึงแล้วว่าคุณ จำกัด ไฟล์ส่วนหัวไว้เพียงการประกาศ พวกเขาเป็นเพียงส่วนหัวเท่านั้น หากคุณต้องการรวมรหัสคุณรวบรวมมันเป็นห้องสมุดและเชื่อมโยงมันขึ้น


2

ฉันนำการใช้งานทั้งหมดออกจากข้อกำหนดของคลาส ฉันต้องการที่จะให้ความคิดเห็น doxygen ออกจากคำจำกัดความของชั้นเรียน


1
ฉันรู้ว่ามันสาย แต่ downvoters (หรือโซเซียลลิสต์) สนใจที่จะแสดงความเห็นว่าทำไม? ดูเหมือนว่าคำสั่งที่สมเหตุสมผลสำหรับฉัน เราใช้ Doxygen และปัญหาก็เกิดขึ้นอย่างแน่นอน
TED

2

ฉันคิดว่ามันเป็นเรื่องไร้สาระอย่างยิ่งที่จะใส่คำจำกัดความฟังก์ชันทั้งหมดของคุณลงในไฟล์ส่วนหัว ทำไม? เนื่องจากไฟล์ส่วนหัวใช้เป็นส่วนต่อประสานสาธารณะไปยังคลาสของคุณ มันคือด้านนอกของ "กล่องดำ"

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


1

นั่นไม่ได้ขึ้นอยู่กับความซับซ้อนของระบบและการประชุมในบ้านจริงเหรอ?

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

นิยามคลาสใน classname.h
รหัสชั้นเรียนใน
รหัสปฏิบัติการ classnameCode.h ใน classname.cpp

สิ่งนี้แยกการจำลองที่ผู้ใช้สร้างขึ้นจากคลาสพื้นฐานที่ผู้พัฒนาสร้างขึ้นและทำงานได้ดีที่สุดในสถานการณ์

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


1
อะไรคือความแตกต่างระหว่าง "รหัสชั้นเรียน" และ "รหัสปฏิบัติการ"?
TED

อย่างที่ฉันบอกว่ามันเป็นเครื่องจำลองระบบประสาท: ผู้ใช้สร้างแบบจำลองที่ปฏิบัติการได้ซึ่งสร้างขึ้นในคลาสจำนวนมากที่ทำหน้าที่เป็นเซลล์ประสาท ฯลฯ ดังนั้นรหัสของเราเป็นเพียงคลาสที่ไม่สามารถทำอะไรได้ด้วยตัวเองและผู้ใช้งาน ทำให้ตัวจำลองทำสิ่งต่างๆ
Ed James

โดยทั่วไปคุณไม่สามารถพูดว่า "ไม่สามารถทำอะไรด้วยตัวเองได้" สำหรับคนส่วนใหญ่ (ถ้าไม่ใช่ทั้งหมด) ของรายการส่วนใหญ่? คุณกำลังบอกว่ารหัส "หลัก" ไปใน cpp แต่ไม่มีอะไรทำ?
TED

ในสถานการณ์นี้มันแตกต่างกันเล็กน้อย รหัสที่เราเขียนนั้นเป็นห้องสมุดและผู้ใช้สร้างแบบจำลองของพวกเขาที่ด้านบนของสิ่งนี้ซึ่งสามารถรันได้จริง ลองคิดดูเช่น openGL -> คุณจะได้รับฟังก์ชั่นและวัตถุจำนวนมาก แต่ไม่มีไฟล์ cpp ที่สามารถเรียกใช้พวกเขาพวกเขาไม่มีประโยชน์
Ed James

0

รหัสเทมเพลตควรอยู่ในส่วนหัวเท่านั้น นอกเหนือจากนั้นคำจำกัดความทั้งหมดยกเว้นอินไลน์ควรอยู่ใน. cpp อาร์กิวเมนต์ที่ดีที่สุดสำหรับเรื่องนี้คือการใช้งานไลบรารี std ซึ่งเป็นไปตามกฎเดียวกัน คุณจะไม่เห็นด้วยกับนักพัฒนา std lib จะถูกเกี่ยวกับเรื่องนี้


ซึ่ง stdlibs? libstdc++ดูเหมือนว่าGCC (AFAICS) จะไม่ใส่อะไรในsrcเกือบทุกอย่างincludeไม่ว่าจะเป็น 'ต้อง' อยู่ในส่วนหัว ดังนั้นฉันไม่คิดว่านี่เป็นการอ้างอิงที่ถูกต้อง / มีประโยชน์ อย่างไรก็ตามฉันไม่คิดว่า stdlib นั้นเป็นแบบอย่างสำหรับรหัสผู้ใช้: พวกเขาเขียนโดย coders ที่มีทักษะสูง แต่จะใช้ไม่อ่าน: พวกมันแยกความซับซ้อนสูงออกไปซึ่งผู้เข้ารหัสส่วนใหญ่ไม่จำเป็นต้องคิด ต้องการความน่าเกลียด_Reserved __namesทุกที่เพื่อหลีกเลี่ยงความขัดแย้งกับผู้ใช้ความคิดเห็น & การเว้นวรรคต่ำกว่าสิ่งที่ฉันแนะนำ ฯลฯ พวกเขาเป็นแบบอย่างในทางที่แคบ
underscore_d

0

ฉันคิดว่าเพื่อนร่วมงานของคุณถูกต้องตราบใดที่เขาไม่ได้เข้าสู่กระบวนการเพื่อเขียนโค้ดที่สามารถใช้งานได้ในส่วนหัว ฉันคิดว่ามีความสมดุลที่เหมาะสมคือการทำตามเส้นทางที่ระบุโดย GNAT Ada ที่ไฟล์. ad ให้คำจำกัดความอินเทอร์เฟซที่เพียงพออย่างสมบูรณ์แบบของแพ็คเกจสำหรับผู้ใช้และลูกของมัน

คุณเคยดูฟอรัมนี้กับคำถามล่าสุดเกี่ยวกับ Ada ที่ผูกไว้กับห้องสมุด CLIPS ที่คุณเขียนเมื่อหลายปีก่อนและสิ่งใดที่ไม่พร้อมใช้งานอีกต่อไป (ตอนนี้ปิดหน้าเว็บที่เกี่ยวข้องแล้ว) แม้ว่าจะทำกับเวอร์ชันคลิปเก่าการเชื่อมโยงนี้อาจเป็นตัวอย่างการเริ่มต้นที่ดีสำหรับบางคนที่เต็มใจใช้กลไกอนุมาน CLIPS ภายในโปรแกรม Ada 2012


1
ฮ่า ๆ. 2 ปีต่อมานี่เป็นวิธีที่แปลกประหลาดในการจับคน ฉันจะตรวจสอบว่าฉันยังมีสำเนาอยู่หรือไม่ แต่ส่วนใหญ่ไม่มี ฉันทำอย่างนั้นสำหรับชั้นเรียน AI ดังนั้นฉันจึงสามารถทำรหัสของฉันใน Ada ได้ แต่ตั้งใจทำโปรเจกต์ CC0 (โดยไม่มีหลักความหมาย) โดยหวังว่าจะมีใครบางคนเอามันลงคอและทำอะไรกับมัน
TED
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.