เหตุใด C ++ จึงต้องการไฟล์ส่วนหัวแยกต่างหาก


138

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

C ++ ได้รับการให้สัตยาบันในปี 1998 ดังนั้นทำไมมันจึงออกแบบวิธีนี้ ข้อดีของการมีไฟล์ส่วนหัวแยกกันคืออะไร


ติดตามคำถาม:

คอมไพเลอร์หาไฟล์. cpp ด้วยรหัสในวิธีใดเมื่อฉันรวมเป็นไฟล์. h มันสันนิษฐานว่าไฟล์. cpp มีชื่อเดียวกันกับไฟล์. h หรือไม่จริง ๆ แล้วค้นหาไฟล์ทั้งหมดในแผนผังไดเรกทอรีหรือไม่


2
หากคุณต้องการแก้ไขไฟล์เดียว lzz ชำระเงิน (www.lazycplusplus.com)
Richard Corden

3
แน่นอนที่ซ้ำกัน: stackoverflow.com/questions/333889 ซ้ำใกล้เคียง: stackoverflow.com/questions/752793
Peter Mortensen

คำตอบ:


105

ดูเหมือนว่าคุณกำลังถามเกี่ยวกับการแยกคำจำกัดความจากการประกาศแม้ว่าจะมีการใช้งานอื่นสำหรับไฟล์ส่วนหัว

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

เหตุผลที่คุณอาจต้องการแยกคือ:

  1. เพื่อปรับปรุงเวลาสร้าง
  2. เพื่อเชื่อมโยงกับรหัสโดยไม่มีแหล่งที่มาสำหรับคำจำกัดความ
  3. เพื่อหลีกเลี่ยงการทำเครื่องหมายทุกอย่าง "แบบอินไลน์"

หากคำถามทั่วไปของคุณคือ "เพราะเหตุใด C ++ จึงไม่เหมือนกับ Java?" ฉันต้องถามว่า "ทำไมคุณถึงเขียน C ++ แทน Java?" ;-P

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

ดังนั้น#includeการทดแทนข้อความที่ตรง หากคุณกำหนดทุกอย่างในไฟล์ส่วนหัวพรีโปรเซสเซอร์จะสร้างสำเนาและวางไฟล์ต้นฉบับทุกไฟล์ในโครงการของคุณและป้อนให้กับคอมไพเลอร์ ความจริงที่ว่ามาตรฐาน C ++ นั้นได้รับการยอมรับในปี 1998 นั้นไม่เกี่ยวข้องกับสิ่งนี้ แต่เป็นความจริงที่ว่าสภาพแวดล้อมการรวบรวมสำหรับ C ++ นั้นขึ้นอยู่กับ C อย่างมาก

การแปลงความคิดเห็นของฉันเพื่อตอบคำถามติดตามผลของคุณ:

คอมไพเลอร์หาไฟล์. cpp ได้อย่างไรด้วยรหัสใน

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


3
ในการเพิ่มไปยัง "เหตุผลที่คุณอาจต้องการแยกคือ:" & ฉันสิ่งที่สำคัญที่สุดของไฟล์ส่วนหัวคือ: การแยกการออกแบบโครงสร้างรหัสจากการนำไปใช้เนื่องจาก: A. เมื่อคุณเข้าไปในโครงสร้างที่ซับซ้อนมากที่เกี่ยวข้องกับวัตถุจำนวนมาก ง่ายกว่าในการลอดผ่านไฟล์ส่วนหัวและจดจำว่ามันทำงานร่วมกันได้อย่างไรเสริมด้วยความคิดเห็นส่วนหัวของคุณ B. คนคนหนึ่งไม่ได้ดูแลการกำหนดโครงสร้างของวัตถุทั้งหมดและบางคนก็ดูแลการใช้งานมันทำให้สิ่งต่าง ๆ ที่จัดระเบียบ ฉันคิดว่ามันทำให้โค้ดที่ซับซ้อนอ่านได้ง่ายขึ้น
Andres Canella

ในวิธีที่ง่ายที่สุดที่ฉันสามารถนึกถึงประโยชน์ของการแยกไฟล์ส่วนหัวและ cpp คือการแยก Interface กับการใช้งานซึ่งช่วยอย่างแท้จริงสำหรับโครงการขนาดกลาง / ใหญ่
กฤษณะ Oza

ฉันตั้งใจจะรวมไว้ใน (2) "ลิงก์กับโค้ดโดยไม่มีคำจำกัดความ" ตกลงดังนั้นคุณอาจยังสามารถเข้าถึง repo git ด้วยคำจำกัดความใน แต่ประเด็นก็คือคุณสามารถรวบรวมรหัสของคุณแยกต่างหากจากการใช้งานของการอ้างอิงและจากนั้นเชื่อมโยง หากแท้จริงทั้งหมดที่คุณต้องการคือการแยกส่วนต่อประสาน / การนำไปใช้งานเป็นไฟล์ต่าง ๆ โดยไม่ต้องกังวลเรื่องการสร้างแยกจากกันคุณสามารถทำได้โดยเพียงแค่มี foo_interface.h รวม foo_implementation.h
Steve Jessop

4
@AndresCanella ไม่มันไม่ได้ มันทำให้การอ่านและการบำรุงรักษาไม่ใช่ฝันร้ายของคุณเอง เพื่อให้เข้าใจอย่างถ่องแท้ถึงสิ่งที่ทำในรหัสคุณต้องข้ามไปยังไฟล์ 2n แทนที่จะเป็นไฟล์ n นี่ไม่ใช่สัญกรณ์บิ๊กโอ 2n สร้างความแตกต่างอย่างมากเมื่อเทียบกับแค่ n
Błażej Michalik

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

91

C ++ ทำแบบนั้นเพราะ C ทำแบบนั้นดังนั้นคำถามจริงก็คือทำไม C ถึงทำแบบนั้น? Wikipediaพูดถึงเรื่องนี้เล็กน้อย

ภาษาที่คอมไพล์ใหม่กว่า (เช่น Java, C #) ไม่ใช้การประกาศไปข้างหน้า ตัวระบุจะถูกจดจำโดยอัตโนมัติจากไฟล์ต้นฉบับและอ่านโดยตรงจากสัญลักษณ์ไลบรารีแบบไดนามิก ซึ่งหมายความว่าไม่จำเป็นต้องใช้ไฟล์ส่วนหัว


13
+1 ชมเล็บบนหัว สิ่งนี้ไม่ต้องการคำอธิบายแบบละเอียด
MSalters

6
มันไม่กระทบกับหัวของฉัน :( ฉันยังต้องค้นหาสาเหตุที่ C ++ ต้องใช้การประกาศไปข้างหน้าและทำไมมันไม่รู้จักตัวระบุจากไฟล์ต้นฉบับและอ่านโดยตรงจากสัญลักษณ์ไลบรารีแบบไดนามิกและทำไม C ++ จึงทำเช่นนั้น วิธีเพียงเพราะ C ทำอย่างนั้น: p
อเล็กซานเดอร์เทย์เลอร์

3
และคุณเป็นนักเขียนโปรแกรมที่ดีกว่าที่ทำเช่นนั้น @AlexanderTaylor :)
Donald Byrd

66

บางคนพิจารณาข้อได้เปรียบของไฟล์ส่วนหัว:

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

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

และ C ++ คงไว้ซึ่งระบบนี้เพื่อความเข้ากันได้

วันนี้มันไม่มีเหตุผล มันไม่มีประสิทธิภาพผิดพลาดง่ายและซับซ้อนเกินไป มีวิธีที่ดีกว่าในการแยกอินเทอร์เฟซและการใช้งานถ้านั่นคือเป้าหมาย

อย่างไรก็ตามหนึ่งในข้อเสนอสำหรับ C ++ 0x คือการเพิ่มระบบโมดูลที่เหมาะสมทำให้สามารถรวบรวมรหัสได้คล้ายกับ. NET หรือ Java ลงในโมดูลขนาดใหญ่ทั้งหมดในครั้งเดียวและไม่มีส่วนหัว ข้อเสนอนี้ไม่ได้ทำให้ถูกต้องใน C ++ 0x แต่ฉันเชื่อว่ายังอยู่ในหมวดหมู่ "เรายินดีที่จะทำสิ่งนี้ในภายหลัง" บางทีใน TR2 หรือคล้ายกัน


นี่คือคำตอบที่ดีที่สุดในหน้า ขอบคุณ!
Chuck Le Butt

29

สำหรับความเข้าใจของฉัน (จำกัด - ฉันไม่ใช่นักพัฒนา C) นี่เป็นรากฐานในซีโปรดจำไว้ว่า C ไม่ทราบว่าคลาสหรือเนมสเปซคืออะไรมันเป็นโปรแกรมที่มีความยาวเพียงโปรแกรมเดียว นอกจากนี้ยังต้องประกาศฟังก์ชั่นก่อนใช้งาน

ตัวอย่างเช่นต่อไปนี้ควรให้ข้อผิดพลาดของคอมไพเลอร์:

void SomeFunction() {
    SomeOtherFunction();
}

void SomeOtherFunction() {
    printf("What?");
}

ข้อผิดพลาดควรเป็นที่ "SomeOtherFunction ไม่ได้ประกาศ" เพราะคุณเรียกมันก่อนที่จะมีการประกาศ วิธีหนึ่งในการแก้ไขปัญหานี้คือการย้าย SomeOtherFunction ด้านบน SomeFunction อีกวิธีคือการประกาศฟังก์ชั่นลายเซ็นแรก:

void SomeOtherFunction();

void SomeFunction() {
    SomeOtherFunction();
}

void SomeOtherFunction() {
    printf("What?");
}

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

ตอนนี้จินตนาการว่าคุณมี SomeFunction และ SomeOtherFunction ในสองไฟล์. c ที่แตกต่างกัน จากนั้นคุณต้อง #include "SomeOther.c" ใน Some.c. ตอนนี้เพิ่มฟังก์ชั่น "ส่วนตัว" บางอย่างเพื่อ SomeOther.c เนื่องจาก C ไม่รู้จักฟังก์ชันส่วนตัวฟังก์ชันนั้นจะพร้อมใช้งานใน Some.c เช่นกัน

นี่คือที่มาของไฟล์. h: พวกเขาระบุฟังก์ชั่นทั้งหมด (และตัวแปร) ที่คุณต้องการ 'ส่งออก' จากไฟล์. c ที่สามารถเข้าถึงได้ในไฟล์. c อื่น ๆ ด้วยวิธีนี้คุณจะได้รับสิ่งที่เหมือนขอบเขตสาธารณะ / ส่วนตัว นอกจากนี้คุณสามารถมอบไฟล์. h นี้ให้กับผู้อื่นได้โดยไม่ต้องแชร์ซอร์สโค้ดของคุณ - ไฟล์. h ทำงานกับไฟล์. lib ที่คอมไพล์แล้วเช่นกัน

ดังนั้นเหตุผลหลักคือเพื่อความสะดวกในการป้องกันซอร์สโค้ดและมีการแยกส่วนระหว่างแอพพลิเคชันของคุณเล็กน้อย

นั่นคือ C แม้ว่า C ++ แนะนำคลาสและตัวดัดแปลงส่วนตัว / สาธารณะดังนั้นในขณะที่คุณยังสามารถถามได้ว่าพวกเขาต้องการหรือไม่ C ++ AFAIK ยังต้องการการประกาศฟังก์ชันก่อนใช้งาน นอกจากนี้นักพัฒนา C ++ หลายคนเป็น C devleopers เช่นกันและนำแนวคิดและนิสัยของพวกเขามาใช้กับ C ++ - ทำไมจึงเปลี่ยนสิ่งที่ไม่เสีย


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

3
หากคุณมีแหล่งที่มาซึ่งคุณมักจะไม่มี คอมไพล์ C ++ เป็นรหัสเครื่องที่มีประสิทธิภาพพร้อมข้อมูลเพิ่มเติมเพียงพอสำหรับการโหลดและเชื่อมโยงรหัส จากนั้นคุณชี้ซีพียูที่จุดเริ่มต้นและปล่อยให้มันรัน นี่คือพื้นฐานแตกต่างจาก Java หรือ C # ที่รหัสจะถูกรวบรวมเป็น bytecode ตัวกลางที่มีข้อมูลเมตาในเนื้อหา
DevSolar

ฉันเดาว่าในปี 1972 นั่นอาจเป็นการดำเนินการที่ค่อนข้างแพงสำหรับคอมไพเลอร์
Michael Stum

สิ่งที่ Michael Stum พูด เมื่อกำหนดพฤติกรรมนี้การสแกนเชิงเส้นผ่านหน่วยการแปลเดียวเป็นสิ่งเดียวที่สามารถนำไปปฏิบัติได้จริง
jalf

3
ใช่ - การคอมไพล์ด้วยความขมขื่น 16 ครั้งด้วยการทรมานเทปจำนวนมากไม่ใช่เรื่องเล็กน้อย
MSalters

11

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

ข้อได้เปรียบที่สอง: อนุญาตให้ใช้งานอินเทอร์เฟซร่วมกันได้โดยไม่ต้องแชร์รหัสระหว่างหน่วยต่าง ๆ (ผู้พัฒนาทีมทีม บริษัท ฯลฯ )


1
คุณหมายถึงสิ่งนั้นเช่นใน C # 'คุณจะต้องรวมไฟล์ต้นฉบับไว้ในไฟล์ต้นฉบับอื่น' เพราะเห็นได้ชัดว่าคุณทำไม่ได้ เพื่อประโยชน์ที่สองฉันคิดว่ามันขึ้นอยู่กับภาษามากเกินไป: คุณจะไม่ใช้ไฟล์. h เช่น Delphi
Vlagged

คุณต้องคอมไพล์โครงการทั้งหมดใหม่อีกครั้งดังนั้นข้อได้เปรียบครั้งแรกจะนับจริงๆหรือไม่?
Marius

ตกลง แต่ฉันไม่คิดว่าคุณสมบัติภาษา มันเป็นสิ่งที่ใช้ปฏิบัติได้จริงในการจัดการกับการประกาศ C ก่อนคำจำกัดความ "ปัญหา" มันเหมือนคนที่มีชื่อเสียงพูดว่า "นั่นไม่ใช่ข้อผิดพลาดที่เป็นคุณลักษณะ" :)
38432 neuro ประสาท

@Marius: ใช่มันนับจริง ๆ การเชื่อมโยงโครงการทั้งหมดแตกต่างจากการรวบรวมและเชื่อมโยงโครงการทั้งหมด เมื่อจำนวนไฟล์ในโครงการเพิ่มขึ้นการรวบรวมไฟล์ทั้งหมดทำให้เกิดความรำคาญ @Vlagged: ถูกต้อง แต่ฉันไม่ได้เปรียบเทียบ c ++ กับภาษาอื่น ฉันเปรียบเทียบโดยใช้ไฟล์ต้นฉบับเท่านั้นเทียบกับการใช้ไฟล์ต้นฉบับและไฟล์ส่วนหัว
ลบออก

C # ไม่รวมไฟล์ต้นฉบับในไฟล์อื่น ๆ แต่คุณยังต้องอ้างอิงโมดูล - และทำให้คอมไพเลอร์ดึงไฟล์ต้นฉบับ (หรือสะท้อนกลับเข้าไปในไบนารี่) เพื่อแยกสัญลักษณ์ที่รหัสของคุณใช้
gbjbaanb

5

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

เพื่อชดเชยข้อ จำกัด นี้ C และ C ++ อนุญาตให้มีการประกาศและการประกาศเหล่านี้สามารถรวมอยู่ในโมดูลที่ใช้พวกเขาด้วยความช่วยเหลือของ #include คำสั่งของโปรเซสเซอร์

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

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


ฉันเห็นด้วยกับคุณ. ฉันมีความคิดที่คล้ายกันที่นี่: stackoverflow.com/questions/3702132/…
smwikipedia

4

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

ใช่ ณ จุดนี้ (10 ปีหลังจากมาตรฐาน C ++ แรกและ 20 ปีหลังจากที่เริ่มมีการเติบโตอย่างจริงจังในการใช้งาน) มันง่ายที่จะถามว่าทำไมมันไม่มีระบบโมดูลที่เหมาะสม เห็นได้ชัดว่าภาษาใหม่ใด ๆ ที่ถูกออกแบบในวันนี้จะไม่ทำงานเหมือน C ++ แต่นั่นไม่ใช่จุด C ++

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

ซึ่งหมายความว่าจะทำให้บางสิ่งยากขึ้น (โดยเฉพาะอย่างยิ่งสำหรับผู้ที่เริ่มต้นโครงการใหม่) และบางสิ่งง่ายขึ้น (โดยเฉพาะอย่างยิ่งสำหรับผู้ที่รักษารหัสที่มีอยู่) มากกว่าภาษาอื่น ๆ

ดังนั้นแทนที่จะคาดหวังว่า C ++ จะเปลี่ยนเป็น C # (ซึ่งจะไม่มีประโยชน์เพราะเรามี C # อยู่แล้ว) ทำไมไม่เลือกเครื่องมือที่เหมาะสมสำหรับงาน? ตัวฉันเองฉันพยายามเขียนฟังก์ชันใหม่ ๆ ในภาษาที่ทันสมัย ​​(ฉันใช้ภาษา C #) และฉันมี C ++ ที่มีอยู่จำนวนมากที่ฉันเก็บไว้ในภาษา C ++ เพราะจะไม่มีคุณค่าที่แท้จริงในการเขียนใหม่ ทั้งหมด. พวกมันรวมกันเป็นอย่างดีอยู่แล้วดังนั้นจึงไม่เจ็บปวดอย่างมาก


คุณจะรวม C # และ C ++ ได้อย่างไร ผ่าน COM ไหม
Peter Mortensen

1
มีสามวิธีหลัก "ดีที่สุด" ขึ้นอยู่กับรหัสที่คุณมีอยู่ ฉันใช้ทั้งสาม สิ่งที่ฉันใช้บ่อยที่สุดคือ COM เพราะรหัสที่มีอยู่ของฉันได้รับการออกแบบรอบ ๆ แล้วดังนั้นมันจึงไร้รอยต่อใช้งานได้ดีมากสำหรับฉัน ในสถานที่แปลก ๆ ฉันใช้ C ++ / CLI ซึ่งให้การรวมที่ราบรื่นอย่างไม่น่าเชื่อสำหรับสถานการณ์ใด ๆ ที่คุณยังไม่มีอินเตอร์เฟส COM (และคุณอาจต้องการใช้อินเตอร์เฟส COM ที่มีอยู่แม้ว่าคุณจะมี) ในที่สุดก็มี p / เรียกใช้ซึ่งโดยทั่วไปให้คุณเรียกใช้ฟังก์ชัน C-like ใด ๆ ที่สัมผัสจาก DLL ดังนั้นให้คุณเรียก Win32 Win32 ใด ๆ จาก C # โดยตรง
Daniel Earwicker

4

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

เหตุผลหลักสำหรับไฟล์ส่วนหัวคือการเปิดใช้งานการรวบรวมไฟล์แยกกันและลดการพึ่งพา

ว่าฉันมี foo.cpp และฉันต้องการใช้รหัสจากไฟล์ bar.h / bar.cpp

ฉันสามารถ #include "bar.h" ใน foo.cpp แล้วเขียนโปรแกรมและคอมไพล์ foo.cpp แม้ว่า bar.cpp จะไม่มีอยู่จริง ไฟล์ส่วนหัวทำหน้าที่สัญญากับคอมไพเลอร์ว่าคลาส / ฟังก์ชั่นใน bar.h จะมีอยู่ในเวลาทำงานและมีทุกสิ่งที่จำเป็นต้องทราบแล้ว

แน่นอนถ้าฟังก์ชั่นใน bar.h ไม่มีเนื้อหาเมื่อฉันพยายามเชื่อมโยงโปรแกรมของฉันมันจะไม่เชื่อมโยงและฉันจะได้รับข้อผิดพลาด

ผลข้างเคียงคือคุณสามารถให้ไฟล์ส่วนหัวแก่ผู้ใช้โดยไม่ต้องเปิดเผยซอร์สโค้ดของคุณ

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


3

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

มันเป็นปัญหาขอบเขตจริงๆ


1

C ++ ได้รับการให้สัตยาบันในปี 1998 ดังนั้นทำไมมันจึงออกแบบวิธีนี้ ข้อดีของการมีไฟล์ส่วนหัวแยกกันคืออะไร

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


1

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


1

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

#ifndef MY_HEADER_SWEET_GUARDIAN
#define MY_HEADER_SWEET_GUARDIAN

// [...]
// my header
// [...]

#endif // MY_HEADER_SWEET_GUARDIAN

มันไม่ได้เป็นคุณสมบัติทางภาษา แต่เป็นวิธีที่ใช้งานได้จริงในการจัดการกับการรวมที่หลากหลาย

ดังนั้นฉันคิดว่าเมื่อ C ถูกสร้างขึ้นปัญหาเกี่ยวกับการประกาศล่วงหน้านั้นได้ถูกประเมินต่ำเกินไปและตอนนี้เมื่อใช้ภาษาระดับสูงเช่น C ++ เราต้องจัดการกับสิ่งเหล่านี้

ภาระอีกประการหนึ่งสำหรับผู้ใช้ C ++ ที่ไม่ดี ...


1

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

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