ส่งต่อการประกาศรวมถึง


17

Reduce the number of #include files in header files. It will reduce build times. Instead, put include files in source code files and use forward declarations in header files.

ฉันอ่านมันที่นี่ http://www.yolinux.com/TUTORIALS/LinuxTutorialC++CodingStyle.html

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

คำถาม: ถ้าคลาส (คลาส A) ในส่วนหัวถ้าไม่ได้ใช้คำจำกัดความที่แท้จริงของคลาสเฉพาะ (คลาส B) ดังนั้นการประกาศล่วงหน้าจะช่วยลดเวลาในการคอมไพล์ได้อย่างไร

คำตอบ:


11

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

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

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

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


ขอบคุณสำหรับคำอธิบาย แล้วตกลงเป็นตัวอย่างที่คุณคิดว่ามีสามไฟล์ส่วนหัวvehicle.h, , bus.h รวมไว้โดยและรวมไว้โดย ดังนั้นถ้าผมจะเปลี่ยนในบาง คอมไพเลอร์ไม่เปิดและแยก อีกครั้งหรือไม่ มันรวบรวมอีกครั้งหรือไม่ toybus.hvehicle.hbus.hbus.htoybus.hbus.hvehicle.h
Nayana Adassuriya

1
@NayanaAdassuriya ใช่มันได้รับการรวมและแยกวิเคราะห์ในแต่ละครั้งซึ่งเป็นสาเหตุที่คุณเห็น#pragma onceหรือ#ifndef __VEHICLE_H_พิมพ์การประกาศในไฟล์ส่วนหัวเพื่อป้องกันไฟล์ดังกล่าวไม่ให้ถูกรวมหลายครั้ง (หรือใช้หลายครั้งอย่างน้อยในกรณี ifndef)
Neil

4

เพราะ A.hpp ไม่ต้อง #include B.hpp

ดังนั้น A.hpp จึงกลายเป็น

class B;//or however forward decl works for classes

class A
{
    B* bInstance_;
//...
}

ดังนั้นเมื่อรวม A.hpp แล้ว B.hpp จะไม่ถูกรวมโดยนัยและไฟล์ทั้งหมดที่ขึ้นอยู่กับ A.hpp ไม่จำเป็นต้องทำการคอมไพล์ใหม่ทุกครั้งที่มีการเปลี่ยนแปลง b.hpp


แต่ในไฟล์ต้นฉบับ (A.cpp) ต้องรวมไฟล์ส่วนหัวที่แท้จริง (Bh) ดังนั้นทุกครั้งที่มีการรวบรวม ในที่สุดทั้งสองทาง Bh ต้องการ recompile กับการเปลี่ยนแปลง แตกต่างกันอย่างไร
Nayana Adassuriya

@NayanaAdassuriya ไม่เพราะใช้เพียงตัวชี้ไปที่ B และการเปลี่ยนแปลง B จะไม่ส่งผลกระทบต่อ A.hpp (หรือไฟล์ที่รวมไว้)
ratchet freak

@NayanaAdassuriya: ใช่ A.cpp จะต้องคอมไพล์ใหม่ (ถ้าใช้นิยามของ B ในเนื้อความของเมธอดของ A แต่โดยปกติจะเป็น) แต่ C.cpp ซึ่งใช้ A แต่ไม่ใช่ B โดยตรงจะไม่
Jan Hudec

3

โปรดจำไว้ว่าตัวประมวลผลล่วงหน้า C / C ++ เป็นขั้นตอนการประมวลผลที่แยกจากกันล้วนๆ #includeดึงคำสั่งในเนื้อหาของส่วนหัวรวมและคอมไพเลอร์ที่มีการแยกมัน นอกจากนี้ยังมีการสะสมของแต่ละ.cppแยกออกอย่างสมบูรณ์ดังนั้นความจริงที่ว่าคอมไพเลอร์เพียงแค่แยกวิเคราะห์B.hเมื่อรวบรวมไม่ได้ช่วยให้มันน้อยเมื่อมันต้องการมันอีกครั้งเมื่อรวบรวมB.cpp และอีกครั้งเมื่อรวบรวมA.cpp C.cppและD.cpp. และอื่น ๆ และแต่ละไฟล์เหล่านั้นจะต้องทำการคอมไพล์ใหม่หากไฟล์ใด ๆ ที่รวมอยู่ในนั้นมีการเปลี่ยนแปลง

เพื่อบอกว่าระดับAชั้นการใช้งานBและการเรียนCและDระดับการใช้งานแต่ไม่จำเป็นต้องจัดการA BหากคลาสAสามารถประกาศด้วยเพียงการประกาศไปข้างหน้าBกว่าB.hจะรวบรวมสองครั้ง: เมื่อรวบรวมB.cppและA.cpp(เพราะBยังคงต้องการในAวิธีการของ)

แต่เมื่อA.hรวมB.hก็จะรวบรวมสี่ครั้งเมื่อรวบรวมB.cpp, A.cpp, C.cppและD.cppเป็นต่อมาสองตอนนี้ทางอ้อม ได้แก่B.hเกินไป

นอกจากนี้เมื่อรวมส่วนหัวมากกว่าหนึ่งครั้งตัวประมวลผลล่วงหน้ายังคงต้องอ่านทุกครั้ง มันจะข้ามการประมวลผลเนื้อหาเนื่องจากการป้องกัน#ifdefแต่ก็ยังอ่านและต้องการค้นหาจุดจบของการ์ดซึ่งหมายความว่าต้องแยกคำสั่ง preprocessor ทั้งหมดภายใน

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


+1 การรวมส่วนหัวกลายเป็นปัญหาร้ายแรงเมื่อคุณมีคลาสจำนวนมากพอสมควรไม่ใช่เมื่อมีเพียงสองคลาส A และ B โพสต์อื่น ๆ ทั้งหมดดูเหมือนจะพลาดจุดศูนย์กลางนั้น
Doc Brown

2

การประกาศไปข้างหน้าเร็วกว่าการแยกวิเคราะห์มากกว่าไฟล์ส่วนหัวทั้งหมดที่ตัวเองอาจรวมไฟล์ส่วนหัวมากขึ้น

นอกจากนี้หากคุณเปลี่ยนบางสิ่งในไฟล์ส่วนหัวสำหรับคลาส B ทุกอย่างรวมถึงส่วนหัวนั้นจะต้องทำการคอมไพล์ใหม่ ด้วยการประกาศไปข้างหน้านั่นอาจเป็นไฟล์ต้นฉบับที่มีการใช้งานของ A อยู่เท่านั้น แต่หากส่วนหัวของ A รวมส่วนหัวของ B จริง ๆ ทุกอย่างรวมถึงa.hppจะถูกคอมไพล์ใหม่แม้ว่าจะไม่ได้ใช้ B

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