2009-05-17 9 views
14

मैं बस सोच रहा हूं, कक्षाओं को .h और a .cpp फ़ाइल में अलग करने का पूरा बिंदु क्या है? यह संपादित करना कठिन बनाता है, और यदि आपकी कक्षा को बाहरी उपयोग के लिए .lib या .dll में संकलित नहीं किया जाएगा, तो बिंदु क्या है?सी ++ में दो अलग-अलग फ़ाइलों में कक्षा घोषणा और परिभाषा क्यों डाली गई?

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

उत्तर

15

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

बेशक, आप कह सकते हैं, सब कुछ इनलाइन क्यों न करें। खैर, यदि संकलक आपके इनलाइन सुझाव का सम्मान करता है, तो लंबी कॉल के लिए कोड प्रत्येक कॉल साइट पर दोहराया जाएगा, जिससे आपका कोड अत्यधिक बड़ा हो जाएगा, और संभवत: थ्रैशिंग, कैश समस्याएं, और सभी प्रकार की अनुपयुक्त सामग्री का कारण बन जाएगा।

दूसरी तरफ, यदि कंपाइलर आपको नहीं सुनता है, और कुछ भी इनलाइन नहीं करता है, तो अब आपके पास 2 समस्याएं हैं: 1) आप नहीं जानते कि कौन सी अनुवाद इकाई को आपकी कक्षा परिभाषाएं मिली हैं, और 2) प्रत्येक बार जब आप उन्हें शामिल करते हैं तो संकलक को अभी भी आपकी परिभाषाओं से गुजरना पड़ता है। इसके अलावा, यह सुनिश्चित करने का कोई आसान तरीका नहीं है कि आपने दो अलग-अलग शीर्षकों में अलग-अलग विधि को दो बार गलती से परिभाषित नहीं किया है।

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

वास्तव में, भाषा और पार्सर कैसे बनाया गया था। यह दर्द है, लेकिन आपको बस इससे निपटना होगा।

0

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

आप शायद ही कभी एक फ़ाइल में एक सी ++ प्रोग्राम लिखना चाहते हैं।

+0

मैं एक ज में पूरी कक्षा परिभाषा डालने और यह भी शामिल है, जबकि यह हैडर गार्ड के साथ की रक्षा करने का मतलब –

+0

यदि आप शामिल क्या होता है कि एक ही निष्पादन में एक से अधिक जगह में ज फ़ाइल? उत्तर: आप एक ही कार्य की कई परिभाषाओं के साथ समाप्त होते हैं। - यहां वास्तविक बिंदु यह है कि आप नियमों के साथ सभी तरह की मूर्ख चीजें कर सकते हैं, लेकिन वे हमेशा सामान्य तरीके से अभ्यास में काम नहीं करते हैं। –

3

ठीक है, इस तरह कोड रखने के लाभों में से एक यह है कि यह संकलन समय को कम करता है।

मान लीजिए कि आप अपनी परियोजना पर इन फ़ाइलों करते हैं: यदि आपके पास पहले a.cpp एक वस्तु में संकलित

  • आह
  • a.cpp
  • b.cpp

फ़ाइल एओ, फिर यदि आप एएचb.cpp, compilati में शामिल हैं पर जल्दी होना चाहिए क्योंकि पार्सर को की पूरी घोषणा/परिभाषा को से निपटना नहीं होगा।

2

क्योंकि आपके डीएलएल के भीतर भी अन्य कक्षाएं आपकी कक्षा का उपयोग करेंगी। उन फ़ाइलों को .h सहित, संकलन समय पर कक्षा घोषणा देखना चाहिए। उन्हें परिभाषा नहीं दिखाई देनी चाहिए या कक्षा कार्यों की कई परिभाषाएं होंगी।

0

सी ++ में, कोड मॉड्यूल (ग या सीपीपी फ़ाइलें) के अलग संकलन की आवश्यकता समारोह प्रोटोटाइप उपयोग करने से पहले परिभाषित किया जाना है। यदि आप कहीं और परिभाषित कक्षाओं या विधियों का उपयोग करना चाहते हैं, तो आपको अपनी परिभाषा प्राप्त करने के लिए .h फ़ाइलों को आयात करना होगा। अंत में, लिंकर सुनिश्चित करता है कि .h फ़ाइलों में किए गए सभी वादों को सभी सी/सीपीपी फाइलों द्वारा पूरा किया जा सकता है।

इसके अलावा, यह केवल फाइलों ज को परिभाषित करते हुए इस तरह के बढ़ावा के रूप में बनाया पूरी व्यवस्थाएं करने देता है।

+1

बूस्ट में ज्यादातर हेडर फाइलें शामिल हैं क्योंकि सी ++ टेम्पलेट्स पर भारी निर्भर है (जो कि उदाहरण के लिए टेम्पलेट होने पर पूरे हेडर में पूरी कक्षा परिभाषा डालने का तात्पर्य है)। जहां तक ​​मुझे याद है कि इस ढांचे के कुछ हिस्से में सीपीपी फ़ाइल है, वह एक जो सी ++ टेम्पलेट्स पर भरोसा नहीं करता है: उदाहरण के लिए थ्रेड लाइब्रेरी। –

2

आपका संपादन पुन: बूस्ट एक महत्वपूर्ण अंतर बना देता है। वर्तमान सी ++ मानक में कंपाइलर और लिंकर काम करने के तरीके के कारण टेम्पलेट कक्षाएं हमेशा हेडर में परिभाषित होती हैं। आपको एक ही कारण के लिए हेडर फाइलों में सबसे अधिक टेम्पलेट लाइब्रेरी (केवल बूस्ट नहीं) लागू किए जाएंगे।

5

बूस्ट इसके सभी कोड को इनलाइन नहीं करता है; यह कक्षाओं के लिए टेम्पलेट परिभाषाओं को रेखांकित करता है, यह उम्मीद करता है कि इसके उपभोक्ताओं को तुरंत चालू करने की उम्मीद है, जैसे shared_ptr। कई पुस्तकालयों में ऐसे अनुभाग होते हैं जिन्हें अलग-अलग संकलित करने की आवश्यकता होती है, जैसे boost :: serialization और program_options।

इनलाइन किए जाने वाले अपने कोड बेस के आकार में वृद्धि के रूप में गंभीर नकारात्मक प्रभाव हो सकता है। यह आपके घटकों के बीच युग्मन को बढ़ाता है, आपके संकलन समय को कम करने का उल्लेख नहीं करता है (जो अन्य कारणों से बढ़ावा देता है :)। प्रभावी रूप से, आपकी सभी अनुवाद इकाइयों के पास कार्यक्रम की लगभग पूरी प्रतिलिपि होगी, और एक छोटा सा परिवर्तन आपको सब कुछ पुनर्निर्माण/पुन: स्थापित करने का कारण बनता है। कुछ परियोजनाओं पर, इसमें कई घंटे लग सकते हैं।

मैं वास्तव में इसे संपादित करने के कठिन होने कभी नहीं देखा है; मेरे अनुभव में, यह इंटरफ़ेस और कार्यान्वयन के स्पष्ट पृथक्करण के कारण इसे आसान बनाता है, और मुझे पता है कि मैं कौन सी फाइल ढूंढ रहा हूं उसे ढूंढने के लिए।

+0

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

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