.Cpp फ़ाइल में C ++ नेमस्पेस विधियों को परिभाषित करने का सही तरीका


108

शायद एक डुप्लिकेट, लेकिन खोज करने के लिए एक आसान नहीं ...

हेडर दिया जैसे:

namespace ns1
{
 class MyClass
 {
  void method();
 };
}

मैंने method().cpp फ़ाइल में कई तरह से परिभाषित देखा है:

संस्करण 1:

namespace ns1
{
 void MyClass::method()
 {
  ...
 }
}

संस्करण 2:

using namespace ns1;

void MyClass::method()
{
 ...
}

संस्करण 3:

void ns1::MyClass::method()
{
 ...
}

क्या इसे करने का कोई 'सही' तरीका है? क्या इनमें से कोई भी 'गलत' है कि वे सभी एक ही बात का मतलब नहीं है?


अधिकांश कोड में मैं आमतौर पर तीसरा संस्करण देखता हूं (लेकिन मैं ऐसा क्यों नहीं करता हूं: डी), दूसरा संस्करण केवल विपरीत है क्योंकि नामस्थान को इस अनुमान के साथ जोड़ा गया है।
श्रीअनुबिस

1
दिलचस्प तथ्य के रूप में, विज़ुअल असिस्ट रिफैक्टिंग टूल # 1 या # 3 का उपयोग करके कोड उत्पन्न करने में प्रसन्न हैं, यह इस बात पर निर्भर करता है कि लक्ष्य फ़ाइल में कौन सी शैली पहले से उपयोग में है।
श्री

जवाबों:


51

संस्करण 2 अस्पष्ट और समझने में आसान नहीं है क्योंकि आप नहीं जानते कि कौन सा नामस्थान किसका MyClassहै और यह केवल अतार्किक है (वर्ग फ़ंक्शन समान नामस्थान में नहीं है?)

संस्करण 1 सही है क्योंकि यह दर्शाता है कि नाम स्थान में, आप फ़ंक्शन को परिभाषित कर रहे हैं।

संस्करण 3 सही भी है क्योंकि आपने नेमस्पेस में ::संदर्भित करने के लिए गुंजाइश रिज़ॉल्यूशन ऑपरेटर का उपयोग किया है । मैं संस्करण 3 पसंद करता हूं।MyClass::method ()ns1

Namespaces (C ++) देखें । यह ऐसा करने का सबसे अच्छा तरीका है।


22
# 2 "गलत" बुलाना एक बहुत बड़ा अतिशयोक्ति है। इस तर्क से, सभी प्रतीक नाम "गलत" हैं, क्योंकि वे संभावित रूप से अन्य प्रतीक नामों को अन्य दायरे में छिपा सकते हैं।
दसफोर

यह अतार्किक है। यह ठीक संकलन करेगा (क्षमा करें, जवाब में misexplained), लेकिन आप इसे नाम स्थान के बाहर एक फ़ंक्शन क्यों परिभाषित करेंगे? यह पाठक को भ्रमित करता है। इसके अलावा, जब कई नामस्थानों का उपयोग किया जाता है, तो यह नहीं दिखाया जाता है कि कौन सा नामस्थान MyClass है। संस्करण 1 और 3 इस समस्या को ठीक करते हैं। अंत में, यह गलत नहीं है, लेकिन सिर्फ अस्पष्ट और भ्रमित है।
GILGAMESH

3
मैं @PhoicaicaMacia से सहमत हूं, उपयोग की चाल भयानक है और इससे भ्रम पैदा हो सकता है। एक ऐसे वर्ग पर विचार करें जो एक ऑपरेटर को एक नि: शुल्क फ़ंक्शन के रूप में लागू करता है, शीर्ष लेख में आपके पास namespace N {struct X { void f(); }; X operator==( X const &, X const & ); }अब उपयोग करने वाले कथन के साथ सीपीपी फ़ाइल में आप सदस्य फ़ंक्शन को परिभाषित कर सकते हैं void X::f() {}, लेकिन यदि आप परिभाषित X operator==(X const&, X const&)करते हैं तो आप एक अलग ऑपरेटर को परिभाषित करेंगे। हेडर में परिभाषित किया गया है (आपको वहां मुफ्त फ़ंक्शन के लिए 1 या 3 का उपयोग करना होगा)।
डेविड रॉड्रिग्ज़ - dribeas

1
विशेष रूप से मैं 1 पसंद करता हूं, और लिंक किए गए लेख में उदाहरण वास्तव में कुछ भी हल नहीं करता है पहला उदाहरण 1 का उपयोग करता है, दूसरा 1 और 3 के मिश्रण का उपयोग करता है (कार्यों को योग्यता के साथ परिभाषित किया गया है, लेकिन वे बाहरी नाम स्थान के अंदर परिभाषित हैं)
डेविड रॉड्रिग्ज - dribeas

1
3 में से मैं कहूंगा 1) सबसे अच्छा आईडीई है, लेकिन उस नामस्थान घोषणा के अंदर सब कुछ इंडेंट करने की बजाय कष्टप्रद आदत है और यह कुछ भ्रम जोड़ता है।
लोका

28

5 साल बाद और मैंने सोचा कि मैं इसका उल्लेख करूंगा, जो दोनों अच्छा लग रहा है और बुराई नहीं है

using ns1::MyClass;

void MyClass::method()
{
  // ...
}

3
यह सबसे अच्छा जवाब है। यह सबसे साफ दिखता है, और ओपी के संस्करणों 1 के साथ मुद्दों से बचा जाता है, जो अनायास ही नेमस्पेस में चीजों को ला सकता है, और 2, जो वैश्विक अंतरिक्ष में चीजों को अनायास ही ला सकता है।
ayane_m

हां, यह 3 से कम टाइपिंग का एक बेहतरीन संयोजन है, जबकि अभी भी स्पष्ट रूप से इरादे घोषित कर रहा है।
jb

14

मैं संस्करण 4 (नीचे) का उपयोग कर रहा हूं, क्योंकि यह संस्करण 1 (गूढ़ परिभाषा की मरोड़) और संस्करण 3 (अधिकतम स्पष्ट हो) के अधिकांश लाभों को जोड़ता है। मुख्य नुकसान यह है कि लोगों को इसका इस्तेमाल नहीं किया जाता है, लेकिन जब से मैं इसे तकनीकी रूप से बेहतर मानता हूं तो मेरे पास विकल्प नहीं हैं।

संस्करण 4: नेमस्पेस उपनाम का उपयोग करके पूर्ण योग्यता का उपयोग करें:

#include "my-header.hpp"
namespace OI = outer::inner;
void OI::Obj::method() {
    ...
}

मेरी दुनिया में मैं अक्सर नेमस्पेस उपनामों का उपयोग कर रहा हूं क्योंकि सब कुछ स्पष्ट रूप से योग्य है - जब तक कि यह (जैसे कि चर नाम) नहीं हो सकता है या यह एक ज्ञात अनुकूलन बिंदु (उदाहरण के लिए एक फ़ंक्शन टेम्पलेट में स्वैप) है।


1
जबकि मुझे लगता है कि "यह बेहतर है तो मुझे परवाह नहीं है अगर यह लोग confuses" तर्क त्रुटिपूर्ण है, मैं इस बात से सहमत करने के लिए इस राशि है नेस्टेड नामस्थान के लिए एक अच्छा दृष्टिकोण।
मिस्टर बॉय १५

1
+1 उत्कृष्ट "क्यों-नहीं-मैं-के-विचार-उस" विचार के लिए! (के रूप में "लोगों को [नई तकनीकी रूप से बेहतर चीजों के लिए उपयोग नहीं किया जाता है]", वे इसका इस्तेमाल करेंगे यदि अधिक लोग इसे करते हैं।)
wjl

बस यह सुनिश्चित करने के लिए कि मैं समझ गया हूं, दोनों हैं outerऔर innerपहले से ही अन्य हेडर फ़ाइलों में नामस्थान के रूप में परिभाषित हैं?
डेकुश्रब

4

संस्करण 3 अधिक टाइपिंग की कीमत पर वर्ग और नाम स्थान के बीच संबंध को बहुत स्पष्ट करता है। संस्करण 1 इससे बचता है, लेकिन एक ब्लॉक के साथ सहयोग को पकड़ लेता है। संस्करण 2 इसे छुपाने के लिए जाता है ताकि मैं उससे बचूं।



3

मैं Num.3 (उर्फ वर्बोज़ संस्करण) चुनता हूं। यह अधिक टाइपिंग है, लेकिन इरादा आपके और कंपाइलर के लिए सटीक है। आपके द्वारा पोस्ट की गई समस्या वास्तव में वास्तविक दुनिया की तुलना में सरल है। वास्तविक दुनिया में, परिभाषाओं के लिए अन्य दायरे हैं, न कि केवल वर्ग के सदस्य। आपकी परिभाषाएँ केवल कक्षाओं के साथ बहुत जटिल नहीं हैं - क्योंकि उनका दायरा कभी भी फिर से खुलता नहीं है (नामस्थान, वैश्विक गुंजाइश आदि के विपरीत)।

Num.1 यह वर्गों के अलावा अन्य स्कोपों ​​के साथ विफल हो सकता है - कुछ भी जो फिर से खोला जा सकता है। तो, आप इस दृष्टिकोण का उपयोग करके एक नाम स्थान में एक नया फ़ंक्शन घोषित कर सकते हैं, या आपके इनलाइन को ODR के माध्यम से प्रतिस्थापित किया जा सकता है। आपको कुछ परिभाषाओं (विशेष रूप से, टेम्पलेट विशेषज्ञता) के लिए इसकी आवश्यकता होगी।

Num.2 यह बहुत नाजुक है, विशेष रूप से बड़े कोडबेस में - हेडर और निर्भरता के बदलाव के रूप में, आपका प्रोग्राम संकलित करने में विफल रहेगा।

Num.3 यह आदर्श है, लेकिन टाइप करने के लिए बहुत कुछ है - आपका इरादा किसी चीज को परिभाषित करने का क्या है । यह ठीक यही करता है, और संकलक यह सुनिश्चित करने के लिए किक करता है कि आपने कोई गलती नहीं की है, एक परिभाषा उसके घोषणा पत्र आदि के साथ नहीं है।


3

यह पता चला है कि यह न केवल "कोडिंग-शैली का मामला है"। अंक। 2 शीर्ष लेख फ़ाइल में एक बाहरी घोषित चर को परिभाषित और आरंभ करते समय त्रुटि को जोड़ने की ओर जाता है। मेरे प्रश्न में उदाहरण देखिए। सीपीपी फ़ाइल में नेमस्पेस के भीतर निरंतर की परिभाषा


2

सभी तरीके सही हैं, और हर एक के अपने फायदे और नुकसान हैं।

संस्करण 1 में, आपको प्रत्येक फ़ंक्शन के सामने नेमस्पेस लिखने की अनुमति नहीं है। नुकसान यह है कि आपको एक उबाऊ पहचान मिलेगी, खासकर यदि आपके पास एक से अधिक स्तर के नाम स्थान हैं।

संस्करण 2 में, आप अपना कोड क्लीनर बनाते हैं, लेकिन अगर आपके पास CPP में एक से अधिक नामस्थान लागू हैं, तो कोई दूसरे के कार्यों और चर को सीधे एक्सेस कर सकता है, जिससे आपका नामस्थान बेकार हो जाता है (उस cpp फ़ाइल के लिए)।

संस्करण 3 में, आपको अधिक टाइप करना होगा और आपकी फ़ंक्शन लाइनें स्क्रीन से बड़ी हो सकती हैं, जो डिज़ाइन प्रभावों के लिए खराब है।

एक और तरीका भी है, जिसका इस्तेमाल कुछ लोग करते हैं। यह पहले संस्करण के समान है, लेकिन पहचान की समस्याओं के बिना।

ऐसी बात हे:

#define OPEN_NS1 namespace ns1 { 
#define CLOSE_NS1 }

OPEN_NS1

void MyClass::method()
{
...
}

CLOSE_NS1

यह आपके लिए है कि प्रत्येक परिस्थिति के लिए कौन सा बेहतर है =]


14
मुझे यहाँ मैक्रो का उपयोग करने का कोई कारण नहीं दिख रहा है। यदि आप इंडेंट नहीं करना चाहते हैं, तो केवल इंडेंट न करें। मैक्रो का उपयोग करना सिर्फ कोड को कम स्पष्ट करता है।
दसफोर

1
मुझे लगता है कि आपके द्वारा उल्लेख किया गया आखिरी संस्करण तब भी उपयोगी है जब आप पुराने कंपाइलरों के साथ कोड को संकलित करना चाहते हैं जो नामस्थानों का समर्थन नहीं करते हैं (हां, कुछ डायनासोर अभी भी आसपास हैं)। उस स्थिति में आप मैक्रो को एक #ifdefखंड के अंदर रख सकते हैं ।
लुका मार्टिनी

यदि आप नहीं चाहते हैं तो आपको पहचानने की ज़रूरत नहीं है, लेकिन यदि आप मैक्रोज़ का उपयोग नहीं करते हैं, तो कुछ आईडीई आपके लिए ऐसा करने का प्रयास करेंगे। उदाहरण के लिए, विज़ुअल स्टूडियो में आप पूरे कोड का चयन कर सकते हैं और ऑटो-पहचान के लिए ALT + F8 दबा सकते हैं। यदि आप परिभाषित का उपयोग नहीं करते हैं, तो आप उस कार्यक्षमता को खो देंगे। इसके अलावा, मुझे नहीं लगता कि OPEN_ (नाम स्थान) और CLOSE_ (नाम स्थान) कम स्पष्ट है, यदि आपके पास यह आपके कोडिंग मानक में है। @LucaMartini ने जो कारण दिया वह भी दिलचस्प है।
रेन ग्रीनिर्ट

अगर यह सामान्य किया गया था, तो #define OPEN_NS(X)मुझे लगता है कि यह थोड़ा है उपयोगी है, लेकिन वास्तव में नहीं ... मुझे मैक्रोज़ पर कोई आपत्ति नहीं है, लेकिन यह थोड़ा ओटीटी लगता है। मुझे लगता है कि डाइटमार कुहल का दृष्टिकोण नेस्टेड नेमस्पेस के लिए बेहतर है।
श्री लड़का
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.