เมื่อแบ่งรหัสของคุณออกเป็นหลาย ๆ ไฟล์สิ่งที่ควรจะเป็นไฟล์. h และสิ่งที่ควรจะเป็นไฟล์. cpp?
.hpp
ไฟล์ในขณะที่การประกาศ C เข้าสู่.h
ไฟล์ สิ่งนี้มีประโยชน์มากเมื่อผสมโค้ด C และ C ++ (เช่นโมดูลเดิมใน C)
เมื่อแบ่งรหัสของคุณออกเป็นหลาย ๆ ไฟล์สิ่งที่ควรจะเป็นไฟล์. h และสิ่งที่ควรจะเป็นไฟล์. cpp?
.hpp
ไฟล์ในขณะที่การประกาศ C เข้าสู่.h
ไฟล์ สิ่งนี้มีประโยชน์มากเมื่อผสมโค้ด C และ C ++ (เช่นโมดูลเดิมใน C)
คำตอบ:
ไฟล์ส่วนหัว ( .h
) ได้รับการออกแบบมาเพื่อให้ข้อมูลที่จำเป็นในหลายไฟล์ สิ่งต่างๆเช่นการประกาศคลาสต้นแบบฟังก์ชันและการแจงนับมักจะอยู่ในไฟล์ส่วนหัว ในคำว่า "คำจำกัดความ"
ไฟล์โค้ด ( .cpp
) ได้รับการออกแบบมาเพื่อให้ข้อมูลการใช้งานที่จำเป็นต้องทราบในไฟล์เดียวเท่านั้น โดยทั่วไปแล้วหน่วยงานของฟังก์ชันและตัวแปรภายในที่โมดูลอื่นควร / จะไม่เข้าถึงเป็นสิ่งที่อยู่ใน.cpp
ไฟล์ ในคำว่า "การใช้งาน"
คำถามที่ง่ายที่สุดที่จะถามตัวเองว่าอะไรอยู่ที่ไหน "ถ้าฉันเปลี่ยนสิ่งนี้ฉันจะต้องเปลี่ยนรหัสในไฟล์อื่นเพื่อให้รวบรวมสิ่งต่างๆอีกครั้งหรือไม่" ถ้าคำตอบคือ "ใช่" อาจอยู่ในไฟล์ส่วนหัว หากคำตอบคือ "ไม่" อาจเป็นเพราะอยู่ในไฟล์โค้ด
export
) วิธีเดียวที่ # 1 คือ PIMPL # 2 จะเป็นไปได้หากexport
ได้รับการสนับสนุนและอาจเป็นไปได้โดยใช้ c ++ 0x และextern
เทมเพลต IMO ไฟล์ส่วนหัวใน c ++ สูญเสียประโยชน์ไปมาก
ความจริงก็คือใน C ++ สิ่งนี้ค่อนข้างซับซ้อนกว่าที่องค์กรส่วนหัว / แหล่งที่มาของ C
คอมไพเลอร์มองเห็นไฟล์ซอร์สขนาดใหญ่ (.cpp) หนึ่งไฟล์ที่มีส่วนหัวรวมอยู่อย่างถูกต้อง ซอร์สไฟล์คือหน่วยคอมไพล์ที่จะถูกคอมไพล์เป็นอ็อบเจ็กต์ไฟล์
เนื่องจากหน่วยคอมไพล์หนึ่งหน่วยอาจต้องการข้อมูลเกี่ยวกับการนำไปใช้งานในหน่วยคอมไพล์อื่น ดังนั้นเราสามารถเขียนตัวอย่างการนำฟังก์ชันไปใช้ในแหล่งเดียวและเขียนการประกาศฟังก์ชันนี้ในแหล่งอื่นที่จำเป็นต้องใช้
ในกรณีนี้มีสำเนาข้อมูลเดียวกันสองชุด ซึ่งชั่วร้าย ...
วิธีแก้ปัญหาคือการแบ่งปันรายละเอียดบางอย่าง ในขณะที่การนำไปใช้งานควรจะยังคงอยู่ใน Source การประกาศสัญลักษณ์ที่ใช้ร่วมกันเช่นฟังก์ชันหรือคำจำกัดความของโครงสร้างคลาส enums ฯลฯ อาจจำเป็นต้องแชร์
ส่วนหัวใช้เพื่อใส่รายละเอียดที่แชร์เหล่านั้น
ย้ายไปที่ส่วนหัวของการประกาศสิ่งที่ต้องใช้ร่วมกันระหว่างแหล่งที่มาหลายแหล่ง
ใน C ++ มีสิ่งอื่น ๆ ที่สามารถใส่ไว้ในส่วนหัวได้เนื่องจากต้องการแชร์ด้วยเช่นกัน:
ย้ายไปที่ส่วนหัวทุกสิ่งที่ต้องแชร์รวมถึงการใช้งานร่วมกัน
ใช่. อันที่จริงมีหลายสิ่งหลายอย่างที่อาจอยู่ใน "ส่วนหัว" (เช่นใช้ร่วมกันระหว่างแหล่งที่มา)
กลายเป็นเรื่องซับซ้อนและในบางกรณี (การอ้างอิงแบบวงกลมระหว่างสัญลักษณ์) ไม่สามารถเก็บไว้ในส่วนหัวเดียวได้
ซึ่งหมายความว่าในกรณีที่รุนแรงคุณสามารถมี:
ลองจินตนาการว่าเรามี MyObject ที่เป็นเทมเพลต เราสามารถมี:
// - - - - MyObject_forward.hpp - - - -
// This header is included by the code which need to know MyObject
// does exist, but nothing more.
template<typename T>
class MyObject ;
.
// - - - - MyObject_declaration.hpp - - - -
// This header is included by the code which need to know how
// MyObject is defined, but nothing more.
#include <MyObject_forward.hpp>
template<typename T>
class MyObject
{
public :
MyObject() ;
// Etc.
} ;
void doSomething() ;
.
// - - - - MyObject_implementation.hpp - - - -
// This header is included by the code which need to see
// the implementation of the methods/functions of MyObject,
// but nothing more.
#include <MyObject_declaration.hpp>
template<typename T>
MyObject<T>::MyObject()
{
doSomething() ;
}
// etc.
.
// - - - - MyObject_source.cpp - - - -
// This source will have implementation that does not need to
// be shared, which, for templated code, usually means nothing...
#include <MyObject_implementation.hpp>
void doSomething()
{
// etc.
} ;
// etc.
ใน "ชีวิตจริง" มักจะซับซ้อนน้อยกว่า โค้ดส่วนใหญ่จะมีเฉพาะส่วนหัว / แหล่งที่มาที่เรียบง่ายโดยมีโค้ดอินไลน์บางส่วนในซอร์ส
แต่ในกรณีอื่น ๆ (อ็อบเจ็กต์ที่เทมเพลตซึ่งรู้จักกัน) ฉันต้องมีสำหรับแต่ละอ็อบเจ็กต์การประกาศและส่วนหัวการนำไปใช้งานแยกกันโดยมีซอร์สที่ว่างเปล่ารวมถึงส่วนหัวเหล่านั้นเพื่อช่วยให้ฉันเห็นข้อผิดพลาดในการคอมไพล์
อีกเหตุผลหนึ่งในการแบ่งส่วนหัวออกเป็นส่วนหัวที่แยกจากกันอาจเป็นการเร่งความเร็วในการรวบรวม จำกัด ปริมาณของสัญลักษณ์ที่แยกวิเคราะห์ตามความจำเป็นที่เข้มงวดและหลีกเลี่ยงการคอมไพล์ซ้ำโดยไม่จำเป็นของแหล่งที่มาซึ่งใส่ใจเฉพาะการประกาศไปข้างหน้าเมื่อการปรับใช้วิธีการแบบอินไลน์เปลี่ยนไป
คุณควรทำให้การจัดระเบียบรหัสของคุณง่ายที่สุดเท่าที่จะเป็นไปได้และแบบแยกส่วนมากที่สุด ใส่ไฟล์ต้นฉบับให้มากที่สุด แสดงเฉพาะในส่วนหัวเท่านั้นสิ่งที่ต้องแชร์
แต่วันที่คุณมีการพึ่งพาแบบวงกลมระหว่างอ็อบเจ็กต์เทมเพลตอย่าแปลกใจถ้าองค์กรโค้ดของคุณค่อนข้าง "น่าสนใจ" มากกว่าที่องค์กรส่วนหัว / แหล่งที่มาธรรมดา
^ _ ^
นอกเหนือจากคำตอบอื่น ๆ ทั้งหมดฉันจะบอกคุณว่าสิ่งที่คุณไม่ได้วางไว้ในไฟล์ส่วนหัว:
using
การประกาศ (สิ่งที่พบบ่อยที่สุดusing namespace std;
) ไม่ควรปรากฏในไฟล์ส่วนหัวเนื่องจากจะทำให้เนมสเปซของไฟล์ต้นทางที่รวมอยู่ .
using
เพื่อนำสิ่งต่างๆเข้าสู่เนมสเปซส่วนกลางในส่วนหัว
static inline
ใน C99 เนื่องจากมีบางอย่างเกี่ยวข้องกับสิ่งที่เกิดขึ้นเมื่อคุณรวมการเชื่อมโยงภายในกับเทมเพลต เนมสเปซ Anon ให้คุณ "ซ่อน" ฟังก์ชันในขณะที่รักษาการเชื่อมโยงภายนอก
สิ่งที่รวบรวมเป็นศูนย์ (zero binary footprint) จะไปอยู่ในไฟล์ส่วนหัว
ตัวแปรไม่ได้รวมเข้ากับอะไรเลย แต่การประกาศประเภททำ (เพราะพวกเขาอธิบายว่าตัวแปรทำงานอย่างไร)
ฟังก์ชันทำไม่ได้ แต่ฟังก์ชันแบบอินไลน์ทำ (หรือมาโคร) เนื่องจากสร้างโค้ดเฉพาะที่เรียกเท่านั้น
เทมเพลตไม่ใช่โค้ดเป็นเพียงสูตรสำหรับสร้างโค้ดเท่านั้น ดังนั้นพวกเขาจึงไปในไฟล์ h ด้วย
โดยทั่วไปคุณใส่การประกาศในไฟล์ส่วนหัวและข้อกำหนดในไฟล์การนำไปใช้งาน (.cpp) ข้อยกเว้นคือเทมเพลตซึ่งคำจำกัดความจะต้องอยู่ในส่วนหัวด้วย
คำถามนี้และคำถามที่คล้ายกับคำถามนี้ถูกถามบ่อยใน SO - ดูทำไมต้องมีไฟล์ส่วนหัวและไฟล์. cpp ใน C ++ และไฟล์ส่วนหัว C ++ การแยกโค้ดเช่น
การประกาศคลาสและฟังก์ชันของคุณรวมถึงเอกสารประกอบและคำจำกัดความสำหรับฟังก์ชัน / วิธีการแบบอินไลน์ (แม้ว่าบางคนชอบที่จะใส่ไว้ในไฟล์. inl แยกต่างหาก)
ไฟล์ส่วนหัวส่วนใหญ่มีโครงกระดูกคลาสหรือการประกาศ (ไม่เปลี่ยนแปลงบ่อย)
และไฟล์ cpp มีการใช้งานคลาส (เปลี่ยนแปลงบ่อย)
ไฟล์ส่วนหัว (.h) ควรใช้สำหรับการประกาศคลาสโครงสร้างและวิธีการต้นแบบ ฯลฯ การนำอ็อบเจ็กต์เหล่านั้นไปใช้ใน cpp
ใน. h
class Foo {
int j;
Foo();
Foo(int)
void DoSomething();
}
ฉันคาดหวังว่าจะได้เห็น:
คำตอบจริงๆคือสิ่งที่ไม่ควรใส่:
ส่วนหัวกำหนดบางสิ่ง แต่ไม่ได้บอกอะไรเกี่ยวกับการนำไปใช้งาน (ไม่รวมเทมเพลตใน "metafore" นี้
จากที่กล่าวไปคุณต้องแบ่ง "คำจำกัดความ" ออกเป็นกลุ่มย่อยในกรณีนี้คำจำกัดความสองประเภท
ตอนนี้ฉันกำลังพูดถึงกลุ่มย่อยแรกแน่นอน
ส่วนหัวมีไว้เพื่อกำหนดเค้าโครงของโครงสร้างของคุณเพื่อช่วยให้ซอฟต์แวร์ที่เหลือใช้การนำไปใช้งานได้ คุณอาจต้องการเห็นว่ามันเป็น "นามธรรม" ของการนำไปใช้งานซึ่งพูดได้อย่างไร้เสียง แต่ฉันคิดว่ามันเหมาะกับกรณีนี้มากทีเดียว
ตามที่ผู้โพสต์ก่อนหน้านี้ได้กล่าวและแสดงให้คุณประกาศพื้นที่การใช้งานส่วนตัวและสาธารณะรวมถึงตัวแปรส่วนตัวและสาธารณะด้วย ตอนนี้ฉันไม่ต้องการออกแบบโค้ดที่นี่ แต่คุณอาจต้องการพิจารณาสิ่งที่คุณใส่ในส่วนหัวของคุณเนื่องจากนั่นคือ Layer ระหว่างผู้ใช้ปลายทางและการนำไปใช้งาน
ส่วนหัว (.h)
ร่างกาย (.cpp)
ตามหลักทั่วไปคุณวางส่วนที่ "แชร์" ของโมดูลไว้ที่. h (ส่วนที่โมดูลอื่น ๆ ต้องสามารถมองเห็นได้) และส่วน "ไม่แชร์" บน. cpp
PD: ใช่ฉันได้รวมตัวแปรส่วนกลางแล้ว ฉันเคยใช้มันมาบ้างแล้วและสิ่งสำคัญคืออย่ากำหนดไว้ในส่วนหัวไม่เช่นนั้นคุณจะได้รับโมดูลจำนวนมากโดยแต่ละโมดูลจะกำหนดตัวแปรของตัวเอง
แก้ไข: แก้ไขหลังจากความคิดเห็นของเดวิด