2010-02-19 20 views
27

में मैं कुछ सी ++ कोड पढ़ रहा हूं और ध्यान दें कि शीर्षलेख फ़ाइलों और .cpp फ़ाइलों में "# शामिल" हैं। मुझे लगता है कि अगर मैं फ़ाइल में सभी "#include" को स्थानांतरित करता हूं, तो हम foo.cpp कहें, इसकी 'हेडर फ़ाइल foo.hh और foo.cpp में केवल foo शामिल करें। कोड को वैसे भी काम करना चाहिए जैसे मुद्दों का कोई खाता नहीं लेना कमियां, दक्षता और आदि।जहां "शामिल" होना चाहिए C++

मुझे पता है कि मेरा "अचानक" विचार किसी भी तरह से एक बुरा विचार होना चाहिए, लेकिन इसकी सटीक कमी क्या है? मैं C++ के लिए नया हूं इसलिए मैं अपने द्वारा इस प्रश्न का उत्तर देने से पहले सी ++ पुस्तक को बहुत कुछ नहीं पढ़ना चाहता हूं। इसलिए अपनी मदद के लिए यहां प्रश्न छोड़ दें। अग्रिम में धन्यवाद।

उत्तर

30

एक नियम के रूप में, जब आप कर सकते हैं तो .cpp फ़ाइलों में शामिल करें, और केवल .h फ़ाइलों में जब यह संभव नहीं है।

आप कई मामलों में अन्य शीर्षकों से हेडर शामिल करने की आवश्यकता को हटाने के लिए forward declarations का उपयोग कर सकते हैं: यह संकलन समय को कम करने में मदद कर सकता है जो आपकी परियोजना के बढ़ने के साथ एक बड़ा मुद्दा बन सकता है। शुरुआत में आने की यह एक अच्छी आदत है क्योंकि इसे बाद की तारीख में हल करने की कोशिश की जा रही है (जब यह पहले से ही एक समस्या है) एक पूर्ण दुःस्वप्न हो सकता है।

इस नियम का अपवाद टेम्पलेट वर्ग (या फ़ंक्शंस) है: उन्हें उपयोग करने के लिए आपको पूर्ण परिभाषा देखने की आवश्यकता है, जिसका आमतौर पर उन्हें हेडर फ़ाइल में डालने का अर्थ होता है।

+1

"बाहरी टेम्पलेट" की आपकी व्याख्या बहुत इच्छापूर्ण सोच है। आप निराश होंगे। –

+0

@nobugz: ओह? वास्तव में? Goddam यह मुझे उम्मीद है कि यह नहीं है ... टेम्पलेट संकलन गति सी ++ के बारे में सबसे बुरी चीजों में से एक है। उन लोगों के कार्यान्वयन को छिपाने में सक्षम होने के नाते जिन्हें उन्हें देखने की आवश्यकता नहीं है, वे असली वरदान होंगे। – jkp

+0

ऐसा लगता है कि नए निर्यात टेम्पलेट को 'निर्यात' के साथ भ्रमित करने वाला है (जो कि छोड़ दिया गया है)। http://www.cppreference.com/wiki/keywords/export – luke

5

आप अपने हेडर फ़ाइल सहित अन्य सभी फ़ाइलों को पारदर्शी रूप से अपने शीर्षलेख में सभी #include एस भी शामिल करेंगे।

सी ++ (सी में) #include#include डी के स्थान पर #include डी फ़ाइल में बस सभी टेक्स्ट डालने से प्रीप्रोसेसर द्वारा संभाला जाता है। तो #include के बहुत से आप सचमुच अपने compilable फ़ाइल के आकार को सैकड़ों किलोबाइट्स पर दावा कर सकते हैं - और कंपाइलर को यह सब एक फ़ाइल के लिए पार्स करने की आवश्यकता है। ध्यान दें कि अलग-अलग स्थानों में शामिल एक ही फ़ाइल को प्रत्येक स्थान पर फिर से दोहराया जाना चाहिए जहां यह #include डी है! यह संकलन को क्रॉल में धीमा कर सकता है।

यदि आपको अपने शीर्षलेख में चीजों को घोषित करने (लेकिन परिभाषित नहीं) की आवश्यकता है, तो एस के बजाय forward declaration का उपयोग करें।

+0

या, अधिक सही ढंग से, जब भी आप कर सकते हैं तो आपकी .h फ़ाइलों में '# शामिल' की बजाय आगे की घोषणा का उपयोग करें। कभी-कभी यह अपरिहार्य है। उदाहरण के लिए, यदि कक्षा ए में कक्षा बी का डेटा सदस्य है, तो एएच में बीएच शामिल करना होगा। –

1

यदि आप # सीपीपी फाइलों को शामिल करते हैं, तो आप शायद लिंकर से "एकाधिक परिभाषा" त्रुटियों के भार के साथ समाप्त हो जाएंगे। आप सिद्धांत में # सब कुछ एक एकल अनुवाद इकाई में शामिल कर सकते हैं, लेकिन इसका मतलब यह भी है कि हर बार जब आप एक फ़ाइल में बदलाव करते हैं तो सबकुछ फिर से बनाया जाना चाहिए। वास्तविक दुनिया की परियोजनाओं के लिए, यह अस्वीकार्य है, यही कारण है कि हमारे पास लिंकर्स और टूल्स जैसे बनाना है।

+0

@Neil: अगर हेडर सही तरीके से लिखे गए नहीं हैं! – jkp

+0

@jkp।सीपीपी फाइलें हैंडर –

+0

@ नील: मेरा बुरा। हाँ, यह अच्छा अभ्यास नहीं है। – jkp

1

शीर्षलेख फ़ाइलों के भीतर से हेडर फाइलों को शामिल करना ठीक है, इसलिए सी ++ फ़ाइलों में शामिल है, हालांकि, निर्माण समय को कम करने के लिए आम तौर पर एक अन्य शीर्षलेख के भीतर से हेडर फ़ाइल को शामिल करने से बचने के लिए बेहतर होता है जब तक कि पूरी तरह से जरूरी नहीं है, खासकर यदि कई सी ++ फाइलों में शामिल हैं एक ही हेडर

12

हेडर में फ़ाइलें शामिल करना केवल उस शीर्षलेख का समर्थन करने के लिए आवश्यक होना चाहिए। उदाहरण के लिए, यदि आपका हेडर वेक्टर घोषित करता है, तो आपको वेक्टर शामिल करना चाहिए, लेकिन स्ट्रिंग को शामिल करने का कोई कारण नहीं है। आपको एक खाली प्रोग्राम प्राप्त करने में सक्षम होना चाहिए जिसमें केवल उस शीर्षलेख फ़ाइल को शामिल किया गया हो और संकलित हो।

स्रोत कोड के भीतर, आपको निश्चित रूप से कॉल करने के लिए आवश्यक सभी चीज़ों की आवश्यकता है। यदि आपके किसी भी शीर्षलेख को iostream की आवश्यकता नहीं है लेकिन आपको वास्तविक स्रोत के लिए इसकी आवश्यकता है, तो इसे अलग से शामिल किया जाना चाहिए।

फ़ाइल प्रदूषण शामिल है, मेरी राय में, कोड सड़कों के सबसे खराब रूपों में से एक है।

संपादित करें: हे। ऐसा लगता है कि पार्सर> और < प्रतीकों को खाता है।

1

.hh (या .h) फ़ाइलों को घोषणाओं के लिए माना जाता है।

.cpp (या .cc) फ़ाइलों को परिभाषाओं और कार्यान्वयन के लिए माना जाता है।

पहले यह समझें कि # अंतर्निहित कथन शाब्दिक है। #include "foo.h" सचमुच foo.h की सामग्री की प्रतिलिपि बनाता है और इसे चिपकाता है जहां निर्देश शामिल है अन्य फ़ाइल में है।

विचार यह है कि कुछ अन्य फाइलें bar.cpp और baz.cpp शायद कुछ कोड का उपयोग करना चाहें जो foo.cc में मौजूद है। ऐसा करने का तरीका, सामान्य रूप से, बार.cpp और baz.cpp से #include "foo.h" के लिए उन कार्यों या वर्गों की घोषणा प्राप्त करने के लिए होगा, जिन्हें वे उपयोग करना चाहते थे, और फिर लिंक समय पर, लिंकर इन उपयोगों को बार में जोड़ देगा fc.cpp में कार्यान्वयन के लिए .cpp और baz.cpp (यह लिंकर का पूरा बिंदु है)।

यदि आप सब कुछ foo.h में डालते हैं और ऐसा करने का प्रयास करते हैं, तो आपको कोई समस्या होगी। कहें कि foo.h doFoo() नामक एक फ़ंक्शन घोषित करता है। यदि इस फ़ंक्शन की परिभाषा (कोड) foo.cc में है, तो यह ठीक है। लेकिन अगर doFoo() के लिए कोड foo.h में स्थानांतरित किया गया है, और फिर आप foo.hpp, bar.cpp और baz.cpp के अंदर foo.h शामिल करते हैं, तो अब doFoo() नामक फ़ंक्शन के लिए तीन परिभाषाएं हैं, और आपका लिंकर शिकायत करेगा क्योंकि आपको एक ही दायरे में एक ही नाम के साथ एक से अधिक चीज़ों की अनुमति नहीं है।

0

यदि आप "गार्ड शामिल हैं" का उपयोग करते हैं तो आप कई परिभाषा त्रुटियों से बच सकते हैं।

(begin myheader.h) 
#ifndef _myheader_h_ 
#define _myheader_h_ 
struct blah {}; 
extern int whatsit; 
#endif //_myheader_h_ 

अब अगर आप अन्य हेडर फाइल में "myheader.h" # शामिल, यह केवल एक बार शामिल हो जाएगा (_myheader_h_ की वजह से परिभाषित किया जा रहा)। मेरा मानना ​​है कि एमएसवीसी के बराबर कार्यक्षमता के साथ "#pragma एक बार" है।

+0

'#pragma एक बार 'अब तक एक वास्तविक तथ्य है - जीसीसी भी इसका समर्थन करता है, और मेरा मानना ​​है कि कुछ अन्य भी करते हैं। –

1

शीर्षलेख फ़ाइल में # शामिल करने के साथ कुछ भी गलत नहीं है। यह एक बहुत ही आम प्रथा है, आप किसी उपयोगकर्ता को एक पुस्तकालय को बोझ नहीं करना चाहते हैं, यह भी याद रखना कि अन्य अस्पष्ट शीर्षकों की क्या आवश्यकता है।

एक मानक उदाहरण #include <vector> है। आपको वेक्टर कक्षा मिलती है। और वेक्टर वर्ग को ठीक से संकलित करने के लिए आंतरिक सीआरटी हेडर फाइलों की एक छत की आवश्यकता होती है, जिन चीजों को आपको वास्तव में आवश्यकता नहीं होती है और न ही जानना चाहते हैं।

1

जबकि हेडर फ़ाइल में केवल वही चीज़ शामिल होनी चाहिए, जिसकी आवश्यकता है, "आपको इसकी क्या ज़रूरत है" आप जितना सोच सकते हैं उससे अधिक तरल पदार्थ है, और जिस उद्देश्य को आपने हेडर रखा है उस पर निर्भर है। इसका मतलब यह है कि कुछ शीर्षलेख वास्तव में पुस्तकालयों या अन्य कोड के लिए इंटरफ़ेस दस्तावेज़ हैं। उन मामलों में, हेडर में आपकी लाइब्रेरी का सही उपयोग करने के लिए अन्य सभी डेवलपर की आवश्यकता होगी (और शायद # शामिल) शामिल होना चाहिए।

संबंधित मुद्दे