C++ हेडर फ़ाइल में कार्यान्वयन कैसे शामिल हो सकता है?




header-files (4)

ठीक है, किसी भी तरह से C / C ++ विशेषज्ञ नहीं है, लेकिन मुझे लगा कि हेडर फ़ाइल का कार्य फ़ंक्शन को घोषित करना है, फिर C / CPP फ़ाइल को कार्यान्वयन को परिभाषित करना था।

हालांकि, आज रात कुछ C ++ कोड की समीक्षा करते हुए, मुझे यह एक क्लास की हेडर फ़ाइल में मिला ...

public:
    UInt32 GetNumberChannels() const { return _numberChannels; } // <-- Huh??

private:
    UInt32 _numberChannels;

तो हेडर में कार्यान्वयन क्यों है? क्या इसे const कीवर्ड के साथ करना है? क्या वह इनलाइन क्लास विधि है? सीपीपी फ़ाइल में कार्यान्वयन को परिभाषित करने के लिए इस तरह से करने का लाभ / बिंदु क्या है?


ठीक है, किसी भी तरह से C / C ++ विशेषज्ञ नहीं है, लेकिन मुझे लगा कि हेडर फ़ाइल का कार्य फ़ंक्शन को घोषित करना है, फिर C / CPP फ़ाइल को कार्यान्वयन को परिभाषित करना था।

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

इसलिए, उदाहरण के लिए, यदि आपके पास निम्नलिखित फाइलें हैं:

Foo.h:

#ifndef FooH
#define FooH

class Foo
{
public:
    UInt32 GetNumberChannels() const;

private:
    UInt32 _numberChannels;
};

#endif

Foo.cpp:

#include "Foo.h"

UInt32 Foo::GetNumberChannels() const
{
    return _numberChannels;
}

Bar.cpp:

#include "Foo.h"

Foo f;
UInt32 chans = f.GetNumberChannels();

पूर्वप्रक्रमक Foo.cpp और Bar.cpp को अलग-अलग पार्स करता है और निम्नलिखित कोड उत्पन्न करता है जो संकलक तब पार्स करता है:

Foo.cpp:

class Foo
{
public:
    UInt32 GetNumberChannels() const;

private:
    UInt32 _numberChannels;
};

UInt32 Foo::GetNumberChannels() const
{
    return _numberChannels;
}

Bar.cpp:

class Foo
{
public:
    UInt32 GetNumberChannels() const;

private:
    UInt32 _numberChannels;
};

Foo f;
UInt32 chans = f.GetNumberChannels();

Bar.cpp Bar.obj में संकलित करता है और इसमें Foo::GetNumberChannels() कॉल करने के लिए एक संदर्भ होता है। Foo.cpp Foo.obj में संकलित करता है और इसमें Foo::GetNumberChannels() का वास्तविक कार्यान्वयन शामिल है Foo::GetNumberChannels() । संकलन के बाद, लिंकर फिर .obj फ़ाइलों से मेल खाता है और उन्हें अंतिम निष्पादन योग्य बनाने के लिए एक साथ जोड़ता है।

तो हेडर में कार्यान्वयन क्यों है?

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

क्या इसे कॉन्स्टेबल कीवर्ड के साथ करना है?

सं। const कीवर्ड केवल कंपाइलर को इंगित करता है कि विधि उस वस्तु की स्थिति को नहीं बदलेगी, जिसे रनटाइम पर कॉल किया जा रहा है।

सीपीपी फ़ाइल में कार्यान्वयन को परिभाषित करने के लिए इस तरह से करने का लाभ / बिंदु क्या है?

जब प्रभावी ढंग से उपयोग किया जाता है, तो यह कंपाइलर को आमतौर पर तेज और बेहतर अनुकूलित मशीन कोड का उत्पादन करने की अनुमति देता है।


क्लास हेडर फ़ाइल में कार्यान्वयन को ध्यान में रखते हुए काम करता है, क्योंकि मुझे यकीन है कि आपको पता है कि आपने अपना कोड संकलित किया है। const कीवर्ड यह सुनिश्चित करता है कि आप किसी भी सदस्य को न बदलें, यह विधि कॉल की अवधि के लिए उदाहरण को immutable रखता है।


यह वर्ग घोषणा के भीतर परिभाषित एक सदस्य समारोह होने के आधार पर निहित रूप से inline घोषित किया जाता है। इसका मतलब यह नहीं है कि कंपाइलर ने इसे इनलाइन किया है, लेकिन इसका मतलब है कि आप one-definition-rule को नहीं तोड़ेंगे। यह const * से पूरी तरह असंबंधित है। यह फ़ंक्शन की लंबाई और जटिलता से भी संबंधित नहीं है।

यदि यह एक गैर-सदस्यीय कार्य था, तो आपको इसे inline रूप में स्पष्ट रूप से घोषित करना होगा:

inline void foo() { std::cout << "foo!\n"; }

* एक सदस्य समारोह के अंत में अधिक के लिए here देखें।


सादे सी में भी, हेडर फ़ाइल में कोड डालना संभव है। यदि आप ऐसा करते हैं, तो आपको आमतौर पर इसे static या अन्य घोषित करने की आवश्यकता होती है। एक ही हेडर सहित कई .c फाइलें "बहुधा परिभाषित फ़ंक्शन" त्रुटि का कारण बनेंगी।

पूर्वप्रक्रमक में शामिल फ़ाइल शामिल होती है, इसलिए शामिल फ़ाइल में कोड स्रोत फ़ाइल का हिस्सा बन जाता है (कम से कम कंपाइलर के दृष्टिकोण से)।

C ++ के डिजाइनर ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग को अच्छे डेटा छिपाने के साथ सक्षम करना चाहते थे, इसलिए उन्हें बहुत सारे गेटटर और सेटर फ़ंक्शन देखने की उम्मीद थी। वे अनुचित प्रदर्शन का दंड नहीं चाहते थे। इसलिए, उन्होंने C ++ को डिज़ाइन किया ताकि गेटर्स और सेटर न केवल हेडर में घोषित किए जा सकें, बल्कि वास्तव में लागू किए जा सकें, इसलिए वे इनलाइन होंगे। वह फ़ंक्शन जो आपने दिखाया है, एक गेटर है, और जब C ++ कोड संकलित किया जाता है, तो कोई फ़ंक्शन कॉल नहीं होगा; उस मूल्य को प्राप्त करने के लिए कोड को बस संकलित किया जाएगा।

यह एक कंप्यूटर भाषा बनाना संभव है जिसमें हेडर फ़ाइल / स्रोत फ़ाइल भेद नहीं है, लेकिन बस वास्तविक "मॉड्यूल" है जिसे कंपाइलर समझता है। (C ++ ने ऐसा नहीं किया; वे सिर्फ स्रोत फ़ाइलों के सफल सी मॉडल के शीर्ष पर बने हैं और पाठयक्रम में हेडर फाइलें शामिल हैं।) यदि स्रोत फाइलें मॉड्यूल हैं, तो संकलक के लिए मॉड्यूल से कोड निकालना और फिर संभव होगा। उस कोड को इनलाइन करें। लेकिन C ++ ने जिस तरह से इसे लागू किया है वह सरल है।





header-files