C ++ में फॉरवर्ड-डिक्लेयर क्यों जरूरी है
संकलक यह सुनिश्चित करना चाहता है कि आपने वर्तनी की गलतियाँ नहीं की हैं या फ़ंक्शन के लिए गलत तर्क पारित नहीं किए हैं। इसलिए, यह इस बात पर जोर देता है कि इसका उपयोग करने से पहले यह पहले 'ऐड' (या किसी अन्य प्रकार, वर्ग या कार्य) की घोषणा देखता है।
यह वास्तव में संकलक को कोड को मान्य करने का एक बेहतर काम करने की अनुमति देता है, और इसे ढीले छोरों को साफ करने की अनुमति देता है ताकि यह एक साफ दिखने वाली वस्तु फ़ाइल का उत्पादन कर सके। यदि आपको चीजों को घोषित करने की आवश्यकता नहीं है, तो कंपाइलर एक ऑब्जेक्ट फ़ाइल का उत्पादन करेगा जिसमें सभी संभावित अनुमानों के बारे में जानकारी होगी जिसमें फ़ंक्शन 'ऐड' हो सकता है। और लिंक करने वाले को कोशिश करने और काम करने के लिए बहुत ही चतुर तर्क सम्मिलित करने होंगे, जिसे 'एड' करने के लिए आप वास्तव में कॉल करना चाहते हैं, जब 'ऐड' फंक्शन किसी अलग ऑब्जेक्ट में रह सकता है, तो फाइलर उस एड के साथ जुड़ रहा है, जो ऐड का निर्माण करता है। एक dll या exe। यह संभव है कि लिंक करने वाले को गलत ऐड मिल सकता है। मान लें कि आप int add (int a, float b) का उपयोग करना चाहते थे, लेकिन गलती से इसे लिखना भूल गए, लेकिन लिंकर को पहले से मौजूद int add (int a) मिला int b) और सोचा कि यह सही था और इसके बजाय इसका इस्तेमाल किया। आपका कोड संकलित करेगा, लेकिन वह नहीं करेगा जो आपने अपेक्षित किया था।
इसलिए, बस चीजों को स्पष्ट रखने और अनुमान लगाने आदि से बचने के लिए, कंपाइलर आपके द्वारा उपयोग किए जाने से पहले सब कुछ घोषित करने पर जोर देता है।
घोषणा और परिभाषा के बीच अंतर
एक तरफ, एक घोषणा और एक परिभाषा के बीच के अंतर को जानना महत्वपूर्ण है। एक घोषणा केवल यह बताने के लिए पर्याप्त कोड देती है कि कुछ कैसा दिखता है, इसलिए एक फ़ंक्शन के लिए, यह रिटर्न प्रकार, कॉलिंग कन्वेंशन, विधि का नाम, तर्क और उनके प्रकार हैं। लेकिन विधि के लिए कोड की आवश्यकता नहीं है। एक परिभाषा के लिए, आपको घोषणा की आवश्यकता है और फिर फ़ंक्शन के लिए कोड भी।
कैसे अग्रेषण-घोषणाएँ बिल्ड समय को काफी कम कर सकती हैं
आप अपने वर्तमान में .cpp या .h फ़ाइल में एक फ़ंक्शन की घोषणा # शीर्षलेख के साथ कर सकते हैं जिसमें पहले से ही फ़ंक्शन की घोषणा शामिल है। हालाँकि, यह आपके संकलन को धीमा कर सकता है, खासकर यदि आप अपने प्रोग्राम के .cpp के बजाय एक .hp में हेडर लगाते हैं, तो वह सब कुछ के रूप में जो # लिखता है। यदि आप लिख रहे हैं तो सभी हेडर # शामिल होंगे। आपने इसके लिए भी # लिखा था। अचानक, संकलक में #included पृष्ठों और कोड के पृष्ठ होते हैं, जिन्हें उस समय भी संकलित करने की आवश्यकता होती है जब आप केवल एक या दो फ़ंक्शन का उपयोग करना चाहते थे। इससे बचने के लिए, आप फ़ॉरवर्ड-डिक्लेरेशन का उपयोग कर सकते हैं और फ़ाइल के शीर्ष पर स्वयं फ़ंक्शन की घोषणा टाइप करें। यदि आप केवल कुछ फ़ंक्शन का उपयोग कर रहे हैं, तो यह वास्तव में हेडर को हमेशा #including करने की तुलना में आपके संकलन को तेज बना सकता है। वास्तव में बड़ी परियोजनाओं के लिए,
चक्रीय संदर्भों को तोड़ें जहां दो परिभाषाएँ दोनों एक दूसरे का उपयोग करती हैं
इसके अतिरिक्त, आगे-घोषणाएँ आपको चक्र तोड़ने में मदद कर सकती हैं। यह वह जगह है जहाँ दो कार्य दोनों एक दूसरे का उपयोग करने का प्रयास करते हैं। जब ऐसा होता है (और यह पूरी तरह से मान्य चीज़ है), तो आप एक हेडर फ़ाइल को #include कर सकते हैं, लेकिन वह हेडर फ़ाइल आपके द्वारा वर्तमान में लिखी जा रही हेडर फ़ाइल को #include करने की कोशिश करता है .... जो तब अन्य हेडर को # साइन करता है। , जो आप लिख रहे हैं, उसे # शामिल करें। आप प्रत्येक हैडर फ़ाइल के साथ एक चिकन और अंडे की स्थिति में फंस गए हैं, दूसरे को फिर से जोड़ने की कोशिश कर रहे हैं। इसे हल करने के लिए, आप उन फ़ाइलों में से किसी एक में आवश्यक भागों को अग्रेषित-घोषित कर सकते हैं और उस फ़ाइल से #include छोड़ सकते हैं।
उदाहरण के लिए:
फ़ाइल Car.h
#include "Wheel.h" // Include Wheel's definition so it can be used in Car.
#include <vector>
class Car
{
std::vector<Wheel> wheels;
};
फ़ाइल व्हील
हम्म ... कार की घोषणा यहां आवश्यक है क्योंकि व्हील में एक कार के लिए एक संकेतक है, लेकिन कार को यहां शामिल नहीं किया जा सकता है क्योंकि यह एक संकलक त्रुटि के परिणामस्वरूप होगा। यदि Car.h को शामिल किया गया था, तो वह Wheel.h को शामिल करने का प्रयास करेगा जिसमें Car.h शामिल होगा जिसमें Wheel.h शामिल होगा और यह हमेशा के लिए चलेगा, इसलिए इसके बजाय संकलक एक त्रुटि उठाता है। इसके बजाय कार को घोषित करने के लिए समाधान आगे है:
class Car; // forward declaration
class Wheel
{
Car* car;
};
यदि क्लास व्हील में ऐसी विधियाँ होती हैं, जिनमें कार के तरीकों को कॉल करने की आवश्यकता होती है, तो उन तरीकों को Wheel.cpp में परिभाषित किया जा सकता है और Wheel.cpp अब एक चक्र पैदा किए बिना Car.h को शामिल करने में सक्षम है।