तथ्य यह है कि C ++ में, यह कुछ अधिक जटिल है कि C शीर्ष लेख / स्रोत संगठन।
कंपाइलर क्या देखता है?
कंपाइलर एक बड़े स्रोत (.cpp) फ़ाइल को अपने हेडर के साथ ठीक से शामिल देखता है। स्रोत फ़ाइल संकलन इकाई है जिसे एक ऑब्जेक्ट फ़ाइल में संकलित किया जाएगा।
तो, हेडर क्यों आवश्यक हैं?
क्योंकि एक संकलन इकाई को दूसरे संकलन इकाई में कार्यान्वयन के बारे में जानकारी की आवश्यकता हो सकती है। इसलिए एक उदाहरण के लिए एक स्रोत में एक फ़ंक्शन के कार्यान्वयन के लिए लिख सकते हैं, और इस फ़ंक्शन की घोषणा को किसी अन्य स्रोत में उपयोग करने की आवश्यकता है।
इस मामले में, एक ही जानकारी की दो प्रतियां हैं। जो बुराई है ...
इसका समाधान कुछ विवरण साझा करना है। हालांकि कार्यान्वयन स्रोत में रहना चाहिए, साझा किए गए प्रतीकों की घोषणा, जैसे फ़ंक्शन, या संरचनाओं की परिभाषा, कक्षाएं, एनम आदि, को साझा करने की आवश्यकता हो सकती है।
हेडर का उपयोग उन साझा विवरणों को रखने के लिए किया जाता है।
कई स्रोतों के बीच साझा करने की आवश्यकता की घोषणाओं को हेडर पर ले जाएं
और कुछ नहीं?
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.
वाह!
"वास्तविक जीवन" में, यह आमतौर पर कम जटिल होता है। अधिकांश कोड में केवल एक साधारण हेडर / स्रोत संगठन होगा, जिसके स्रोत में कुछ इनबिल्ट कोड होंगे।
लेकिन अन्य मामलों में (एक-दूसरे को जानने वाले टेम्पर्ड ऑब्जेक्ट्स), मुझे प्रत्येक ऑब्जेक्ट के लिए अलग-अलग घोषणा और कार्यान्वयन हेडर के लिए होना चाहिए, उन हेडर सहित एक खाली स्रोत के साथ बस कुछ संकलन त्रुटियों को देखने में मेरी मदद करने के लिए।
हेडर को अलग हेडर में तोड़ने का एक अन्य कारण संकलन को गति देना हो सकता है, प्रतीकों की मात्रा को सीमित करना आवश्यक है, और एक स्रोत के आवश्यक पुनर्संयोजन से बचने के लिए, जो केवल इनलाइन घोषणा के लिए परवाह करता है जब एक इनलाइन विधि कार्यान्वयन बदल गया।
निष्कर्ष
आपको अपने कोड संगठन को यथासंभव सरल और यथासंभव मॉड्यूलर बनाना चाहिए। जितना संभव हो उतना स्रोत फ़ाइल में रखें। केवल हेडर में उजागर करें जिसे साझा करने की आवश्यकता है।
लेकिन जिस दिन आपके पास टेम्प्लेटेड ऑब्जेक्ट्स के बीच परिपत्र निर्भरताएं होंगी, आश्चर्यचकित न हों कि आपका कोड संगठन कुछ और "दिलचस्प" हो गया है, जो सादे हेडर / स्रोत संगठन ...
^ _ ^