จะทำอย่างไรถ้าฉันเกลียดไฟล์ส่วนหัวของ C ++


25

ฉันมักจะสับสนเกี่ยวกับไฟล์ส่วนหัว มันแปลกมาก: คุณรวมไฟล์. h ซึ่งไม่รวม. cpp แต่. cpp จะถูกคอมไพล์ด้วยเช่นกัน

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

ฉันจะจัดการกับการประชุม 2 ไฟล์ได้อย่างมีประสิทธิภาพได้อย่างไร
มีเครื่องมือใดบ้างที่จะช่วยเหลือหรือเปลี่ยนหนึ่งไฟล์ที่มีลักษณะตัวอย่างด้านล่างเป็น. h และ. cpp โดยอัตโนมัติ? (เฉพาะสำหรับ MS VC ++ 2010)

class A
{
...
    Type f(Type a,Type b)
    {
        //implementation here, not in another file!
    }
...
};

Type f(Type a)
{
     //implementation here
}
...

8
คำถามนี้มีสองวิธี .. "ทำไมเราต้องการส่วนหัวเมื่อใช้ c ++" หรือ "คุณคิดว่าภาษาสมัยใหม่ที่ควรจะรวบรวมควรใช้ส่วนหัว?" ตามที่เป็นอยู่มันมี 'ฉันจะทำอย่างไร "และ" ความเกลียดชัง "ในชื่อซึ่งกำหนดปิดธงมากมายเหลือเฟือ
ทิมโพสต์

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

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

5
จะทำอย่างไร? ค้นหาภาษาอื่นหากมันเป็นปัญหากับคุณอย่างมาก
พอลนาธาน

5
เกี่ยวกับ "ไม่สามารถอยู่กับการคัดลอกวาง": เมื่อใดก็ตามที่มีการอัปเดตฟังก์ชั่นหนึ่งจะต้องอัปเดตสถานที่ทั้งหมด เนื่องจากผู้โทรหาได้ยากกว่าการประกาศในไฟล์ส่วนหัวการอัพเดตส่วนหัวจึงเป็นเพียงรายละเอียดเล็กน้อย
Sjoerd

คำตอบ:


15

การเขียน Refactoring Friendly C ++

ใน C ++ คุณไม่จำเป็นต้องใช้ส่วนหัวเลย คุณสามารถกำหนดวัตถุทั้งหมดในไฟล์เดียวกับ C # หรือ Java นักพัฒนา C โดยทั่วไปจะเก็บสายภายนอกในไฟล์ส่วนหัว การโทรภายในทั้งหมดจะถูกกำหนดไว้ในไฟล์. c ด้วยโทเค็นเดียวกันคุณสามารถจองไฟล์ C ++ .h ของคุณสำหรับคลาส / อินเทอร์เฟซ (คลาสนามธรรมเสมือนจริง) / ฯลฯ ที่มีวัตถุประสงค์เพื่อแบ่งปันนอก DLL สำหรับคลาส / structs / interfaces ภายใน ฯลฯ คุณเพียงแค่รวมไฟล์. cpp ที่คุณต้องการ:

#include<myclass.cpp>

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

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

คุณอาจต้องการดูคำถามนี้: เครื่องมือการปรับโครงสร้างที่ดีสำหรับ C ++

C / C ++ แก้ไขไฟล์ส่วนหัว / การนำไปใช้งานได้อย่างไร

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

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

เฉพาะ VS

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


ปัญหาคือฉันแก้ไขคลาสอย่างหนักตลอดเวลาไม่ใช่แค่เพิ่มฟังก์ชั่นใหม่ ฯลฯ
Oleh Prypin

5
@BlaXpirit: ดังนั้นทำไมคุณจึงปรับเปลี่ยนคลาสอย่างหนักตลอดเวลา หนึ่งในแนวคิดที่อยู่เบื้องหลังการออกแบบ OO คือการสร้างหน่วยความจำที่ค่อนข้างเสถียร ถ้าฉันแก้ไขคลาสอย่างหนักฉันต้องการภาษาแบบไดนามิกมากขึ้นเช่น Common Lisp หรือ Python
David Thornley

2
นั่นคือสิ่งที่ฉันทำ ฉันกำลังปรับปรุง / แก้ไข "การบล็อก" และเพิ่มใหม่
Oleh Prypin

C ++ ไม่เคยทำการปรับโครงสร้างใหม่ให้เป็นมิตร แนวคิดของการปรับโครงสร้างใหม่ไม่ได้รับแรงผลักดันจนกว่าจะมีเครื่องมือที่ทำให้มันง่ายใน Java IDEs หมายเหตุ: คุณสมบัติเหล่านั้นอยู่ที่นั่นสำหรับนักพัฒนา Smalltalk และภาษาอื่น ๆ แต่มันไม่ได้กลายเป็นกระแสหลักจนกว่าจะมีผู้คนมากมาย จนถึงตอนนี้ฉันยังไม่เห็นใครบางคนนำมันมาใช้อย่างชาญฉลาดสำหรับ C ++ บางที Resharper จาก JetBrains ฉันรู้ว่ามันใช้รหัส C # และ VB แต่ฉันไม่แน่ใจว่าจะให้การปรับโครงสร้าง C ++ แก่คุณหรือไม่
Berin Loritsch

@Berin: ฉันไปหา C ++ refactoring tools เมื่อสองปีก่อนและพบสองสิ่ง พวกเขาค่อนข้างแพงในเวลานั้นและฉันไม่เห็นรุ่นทดลองดังนั้นฉันไม่รู้ว่าพวกเขาทำอะไร ยิ่งไปกว่านั้นหนึ่งทำงานกับ emacs เท่านั้นซึ่งจะ จำกัด ประสิทธิภาพในร้าน Visual Studio
David Thornley

13

มาเป็นผู้พัฒนา Java

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


2
kthx ฉันค่อนข้างรู้จัก Java แต่คุณไม่สามารถทำให้ Win32 DLLs ระดับต่ำทำได้หรือไม่
Oleh Prypin

41
ฉันไม่รู้ว่าทำไม แต่ 'เป็นผู้พัฒนา Java' อย่างใดดูเหมือนว่าเป็นการดูถูก: D
Oliver Weiler

2
หากคุณต้องการทำระดับต่ำให้ลืมทุกอย่างเกี่ยวกับ 'ภาษาง่าย ๆ ' ค่าใช้จ่ายในระดับต่ำเหงื่อและน้ำตา
Batibix

5
ไม่ใช่คำตอบที่เป็นประโยชน์อย่างยิ่ง
ChrisF

1
@OliverWeiler ฉันไม่รู้สึกว่า "เป็นผู้พัฒนา Java" เป็นการดูถูก ฉันเขียนโปรแกรมทั้งใน C ++ และ Java แต่ความชอบของฉันคือ Java เพราะมันง่ายกว่ามากที่จะนั่งลงและปังรหัสที่ใช้งานได้ (และพกพาได้มากกว่า) หากคุณรู้สึกว่ามีไฟล์ส่วนหัวด้วยเหตุผลบางประการการลองใช้ Java อาจเป็นทางเลือกที่ถูกต้อง (แม้ว่าจะแปลกที่คุณจะเกลียดไฟล์ส่วนหัว
Trixie Wolf

7

คุณอาจสนใจในการแต่งหน้าโปรแกรมจาก Hwaci (ผู้ที่ทำ SQLite และฟอสซิล)

ดูว่าฟอสซิลสร้างขึ้นเพื่อให้มีความคิดได้อย่างไร


5
ผู้ถามยังคงต้องเข้าใจความสัมพันธ์ระหว่าง. h และ. cpp ค่อนข้างดี
งาน

2
ฉันเข้าใจพื้นฐาน คำตอบดูเหมือนจะเป็นสิ่งที่ฉันต้องการ
Oleh Prypin

4

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

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


-1

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

หากเป็นกรณีของคุณฉันขอแนะนำให้ใช้ " .hpp" (หรือน้อยกว่า)นามสกุลไฟล์ .hxx") หรือส่วนต่อท้ายของไฟล์

คุณอาจต้องกำหนดค่าคอมไพเลอร์สภาพแวดล้อมของนักพัฒนาหรือโปรแกรมที่สร้างขึ้น


3
คุณกำลังพูดถึงว่าเมื่อคุณรวมไฟล์เช่น#include <iostream>? สิ่งเหล่านี้ไม่ได้มีไว้สำหรับห้องสมุด GCC เท่านั้น ในความเป็นจริงมันกำหนดไว้ในมาตรฐาน1997 C ++ส่วน 17.3.1.2 ฉันจะหลีกเลี่ยงการตั้งชื่อไฟล์เช่นนั้น คุณทำได้ แต่เหตุผลที่ไลบรารีมาตรฐาน C ++ ทำนั่นอาจเป็นเหตุผลที่จะหลีกเลี่ยงความขัดแย้งในการตั้งชื่อ ฉันพบว่ามันแปลกจริง ๆ เมื่อคอมไพเลอร์เพิ่ม '.h' โดยอัตโนมัติเมื่อคุณรวมส่วนหัวไว้ดูเหมือนว่าฉันไม่ได้มาตรฐาน และฉันไม่เคยเห็นใครก็ตามที่มีส่วนหัวชื่อโดยไม่มีคำต่อท้ายยกเว้นสำหรับไลบรารีมาตรฐาน c ++
vedosity

1
นอกจากนี้ฉันควรทราบว่าคอมไพเลอร์ทั้งหมดที่ฉันใช้ยกเว้นบอร์แลนด์ (ซึ่งฉันเกลียดมาก ๆ ) อย่าเพิ่ม '.h' หรือ '.hpp' หรือ '.hxx' โดยอัตโนมัติเมื่อคุณลอง เพื่อรวมไฟล์ที่ไม่มีคำต่อท้าย อย่าคาดหวังว่า#include <someclass>จะอ่านได้เหมือน#include <someclass.hpp>คอมไพเลอร์ทั้งหมด รหัสของคุณจะแตก
vedosity
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.