आप C ++ में नामस्थान का ठीक से उपयोग कैसे करते हैं?


231

मैं एक जावा बैकग्राउंड से आता हूँ, जहाँ पैकेजों का इस्तेमाल होता है, नेमस्पेस नहीं। मुझे उन कक्षाओं को लगाने के लिए उपयोग किया जाता है जो संकुल में एक पूर्ण ऑब्जेक्ट बनाने के लिए एक साथ काम करते हैं, और फिर बाद में उस पैकेज से उनका पुनः उपयोग करते हैं। लेकिन अब मैं C ++ में काम कर रहा हूं।

आप C ++ में नामस्थान का उपयोग कैसे करते हैं? क्या आप पूरे अनुप्रयोग के लिए एक एकल नाम स्थान बनाते हैं, या क्या आप प्रमुख घटकों के लिए नामस्थान बनाते हैं? यदि हां, तो आप अन्य नामस्थानों में कक्षाओं से ऑब्जेक्ट कैसे बनाते हैं?

जवाबों:


167

नाम स्थान अनिवार्य रूप से पैकेज हैं। उनका उपयोग इस तरह किया जा सकता है:

namespace MyNamespace
{
  class MyClass
  {
  };
}

फिर कोड में:

MyNamespace::MyClass* pClass = new MyNamespace::MyClass();

या, यदि आप हमेशा एक विशिष्ट नाम स्थान का उपयोग करना चाहते हैं, तो आप यह कर सकते हैं:

using namespace MyNamespace;

MyClass* pClass = new MyClass();

संपादित करें: बर्नहार्ड्रस ने जो कहा है, उसके बाद मैं "नेमस्पेस एक्स का उपयोग करते हुए" सिंटैक्स का उपयोग नहीं करने के लिए कहता हूं, मैं आमतौर पर अपने ऑब्जेक्ट्स (यानी पहला उदाहरण मैंने दिखाया) को तुरंत नाम निर्दिष्ट करते हैं।

और जैसा कि आपने नीचे पूछा है , आप जितने चाहें उतने नामस्थानों का उपयोग कर सकते हैं।


25
IMO केवल stdनाम का उपसर्ग लगाने के बजाय प्रतीकों का उपयोग करने के लिए उपयोग करना बेहतर है using। इसलिए मैं हमेशा लिखता हूं std::coutया std::stringअब क्योंकि मैं उन्हें अब फोन करता हूं। मैं कभी नहीं लिखूंगा cout
टॉम सैवेज

5
जब यह बहुत सच है std, तो मैंने व्यक्तिगत रूप से इसे बहुत कम महत्वपूर्ण पाया है जब आप छोटे पुस्तकालयों के साथ काम कर रहे हैं। अक्सर आप बस उपयोग कर सकते हैं using namespace FooBario;, खासकर यदि आप पुस्तकालय से कई प्रकार के उपयोग कर रहे हैं।
जकरियन

4
@ जुकरियन, मैं आपकी बात देख रहा हूं, लेकिन मैं असहमत हूं क्योंकि नाम टकराव (मेरे दिमाग में) ठीक ऐसी छोटी पुस्तकालयों से आने की अधिक संभावना है। अधिकांश लोग सावधान हैं कि वे एसटीएल में उन वर्गों / कार्यों का नाम न दें। उस ने कहा, मैं सहमत हूं कि using namespace X;यदि संभव हो तो हेडर फ़ाइलों में बचा जाना चाहिए।
एलन ट्यूरिंग

12
@LexFridman "अधिकांश लोग वर्ग / कार्यों को एसटीएल में उन लोगों के नाम के समान नहीं रखने के लिए सावधान हैं" - जो कि सही नहीं है। उदाहरण के लिए अगर मैं कुछ विशेष हार्डवेयर के लिए कुछ विशेष I / O कोड लिखने के लिए था, तो मैं कभी भी, कभी भी, mylibrary::endlअपने स्वयं के विशेष न्यूलाइन अनुक्रम का प्रतिनिधित्व करने के अलावा किसी और चीज का उपयोग नहीं करूंगा। मेरा मतलब है, नामों का आविष्कार क्यों?

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

116

सब कुछ कहने से बचने के लिए मार्क इनग्राम ने पहले से ही नामस्थान का उपयोग करने के लिए थोड़ा टिप कहा:

हेडर फ़ाइलों में "नेमस्पेस का उपयोग" निर्देश से बचें - यह प्रोग्राम के सभी हिस्सों के लिए नेमस्पेस खोलता है जो इस हेडर फ़ाइल को आयात करते हैं। कार्यान्वयन फ़ाइलों में (*। Cpp) यह आम तौर पर कोई बड़ी समस्या नहीं है - पूरी तरह से मैं फ़ंक्शन स्तर पर "नेमस्पेस का उपयोग" निर्देश का उपयोग करना पसंद करता हूं।

मुझे लगता है कि नाम स्थान का उपयोग ज्यादातर नामकरण संघर्ष से बचने के लिए किया जाता है - जरूरी नहीं कि आपके कोड संरचना को व्यवस्थित करने के लिए। मैं मुख्य रूप से हेडर फ़ाइलों / फ़ाइल संरचना के साथ C ++ प्रोग्राम आयोजित करता हूँ।

कार्यान्वयन विवरण को छिपाने के लिए कभी-कभी बड़े सी ++ प्रोजेक्ट्स में नामस्थान का उपयोग किया जाता है।

निर्देश का उपयोग करने के लिए अतिरिक्त नोट: कुछ लोग सिर्फ एकल तत्वों के लिए "उपयोग" करना पसंद करते हैं:

using std::cout;  
using std::endl;

2
फ़ंक्शन स्तर पर "नेमस्पेस का उपयोग" करने का एक फायदा है। जैसा कि आप सुझाव देते हैं। .cpp फ़ाइल स्तर या नेमस्पेस {} ब्लॉक स्तर के बजाय .cpp के भीतर सुझाव है कि यह एकल-संकलन-यूनिट बिल्ड के साथ बहुत मदद करता है। "नाम स्थान का उपयोग करना" सकर्मक है, और एक ही इकाई में असतत नामस्थान A {} ब्लॉकों में नामस्थान A के लिए लागू होता है, इसलिए एकल-संकलन-इकाई के लिए आप फ़ाइल या हैंडस्पेस ब्लॉक स्तर पर किए जाने पर सब कुछ का उपयोग करके जल्दी से निर्माण करते हैं।

using std::cout; का उपयोग करने का ऐलान है
कॉन्स्टेंटिन

3
क्या किसी एकल नाम स्थान से एक ही कथन में कई नामों का उपयोग करना संभव है ? कुछ की तरह या यहां तक कि, । using std::cout, std::endl;using std::cout, endl;
अलक्विमिस्ट

using namespace xयदि किसी अन्य नामस्थान के भीतर है, तो हेडर में इसका उपयोग करना ठीक हो सकता है । यह ऐसी चीज नहीं है जिसे मैं सामान्य रूप से सुझाऊंगा लेकिन यह वैश्विक नामस्थान को प्रदूषित नहीं करता है।
प्रिक्सॉलिटिक

79

विंसेंट रॉबर्ट अपनी टिप्पणी में सही है कि आप C ++ में नामस्थानों का उपयोग कैसे ठीक से करते हैं?

नेमस्पेस का उपयोग करना

नाम टकराव से बचने में मदद करने के लिए नाम स्थान का कम से कम उपयोग किया जाता है। जावा में, इसे "org.domain" मुहावरे के माध्यम से लागू किया जाता है (क्योंकि यह माना जाता है कि कोई व्यक्ति अपने डोमेन नाम के अलावा किसी अन्य चीज का उपयोग नहीं करेगा)।

C ++ में, आप अपने मॉड्यूल के सभी कोड को एक नाम स्थान दे सकते हैं। उदाहरण के लिए, एक मॉड्यूल MyModule.dll के लिए, आप इसके कोड को नामस्थान MyModule दे सकते हैं। मैंने MyCompany :: MyProject :: MyModule का उपयोग करते हुए किसी अन्य व्यक्ति को देखा है। मुझे लगता है कि यह ओवरकिल है, लेकिन सभी में, यह मुझे सही लगता है।

"का उपयोग कर"

का उपयोग बड़ी सावधानी से किया जाना चाहिए क्योंकि यह एक नाम स्थान से आपके वर्तमान नामस्थान में प्रभावी रूप से एक (या सभी) प्रतीकों को आयात करता है।

हेडर फ़ाइल में इसे करना बुरा है क्योंकि आपका हेडर इसमें मौजूद हर स्रोत को प्रदूषित करेगा (यह मुझे मैक्रोज़ की याद दिलाता है ...), और यहां तक ​​कि स्रोत फ़ाइल में, फ़ंक्शन स्कोप के बाहर खराब शैली क्योंकि यह वैश्विक दायरे में आयात करेगा नामस्थान से प्रतीक।

"उपयोग" का उपयोग करने का सबसे सुरक्षित तरीका चुनिंदा प्रतीकों को आयात करना है:

void doSomething()
{
   using std::string ; // string is now "imported", at least,
                       // until the end of the function
   string a("Hello World!") ;
   std::cout << a << std::endl ;
}

void doSomethingElse()
{
   using namespace std ; // everything from std is now "imported", at least,
                       // until the end of the function
   string a("Hello World!") ;
   cout << a << endl ;
}

आपको "नाम स्थान std का उपयोग करते हुए" बहुत सारे दिखाई देंगे; ट्यूटोरियल या उदाहरण कोड में। कारण पढ़ने को आसान बनाने के लिए प्रतीकों की संख्या को कम करना है, इसलिए नहीं कि यह एक अच्छा विचार है।

"नेमस्पेस एसटीडी का उपयोग करना ;" स्कॉट मेयर्स द्वारा हतोत्साहित किया गया है (मुझे ठीक से याद नहीं है कि कौन सी पुस्तक है, लेकिन यदि आवश्यक हो तो मैं इसे पा सकता हूं)।

नामस्थान रचना

नाम स्थान पैकेज से अधिक हैं। एक और उदाहरण बज़्ने स्ट्रॉस्ट्रुप की "द सी ++ प्रोग्रामिंग लैंग्वेज" में पाया जा सकता है।

"स्पेशल एडिशन" में, 8.2.8 नेम्पस्पेस संरचना में , वह बताता है कि आप दो नामस्थान AAA और BBB को CCC नामक एक दूसरे में कैसे मिला सकते हैं। इस प्रकार CCC AAA और BBB दोनों के लिए एक उपनाम बन जाता है:

namespace AAA
{
   void doSomething() ;
}

namespace BBB
{
   void doSomethingElse() ;
}

namespace CCC
{
   using namespace AAA ;
   using namespace BBB ;
}

void doSomethingAgain()
{
   CCC::doSomething() ;
   CCC::doSomethingElse() ;
}

आप अपने स्वयं के कस्टम नामस्थान इंटरफ़ेस का निर्माण करने के लिए विभिन्न नामस्थानों से चुनिंदा प्रतीकों को भी आयात कर सकते हैं। मुझे अभी तक इसका व्यावहारिक उपयोग नहीं करना है, लेकिन सिद्धांत रूप में, यह अच्छा है।


क्या आप स्पष्ट कर सकते हैं, कृपया "अपने मॉड्यूल के सभी कोड को एक नाम स्थान दें"? मॉड्यूल को एनकैप्सुलेट करने के लिए अच्छा अभ्यास क्या है। उदाहरण के लिए मेरे पास जटिल संख्याओं का वर्ग है और जटिल संख्याओं से संबंधित बाहरी कार्यों के लिए। यह वर्ग और वे दो कार्य एक नामस्थान में होने चाहिए?
यानपस १०'१६

74

मैंने अन्य उत्तरों में इसका कोई उल्लेख नहीं देखा, इसलिए यहां मेरे 2 कनाडाई सेंट हैं:

"नाम स्थान का उपयोग" विषय पर, एक उपयोगी कथन नाम स्थान उपनाम है, जो आपको सामान्य रूप से एक छोटा नाम देने के लिए, एक नाम स्थान का नाम बदलने की अनुमति देता है। उदाहरण के लिए, इसके बजाय:

Some::Impossibly::Annoyingly::Long:Name::For::Namespace::Finally::TheClassName foo;
Some::Impossibly::Annoyingly::Long:Name::For::Namespace::Finally::AnotherClassName bar;

तुम लिख सकते हो:

namespace Shorter = Some::Impossibly::Annoyingly::Long:Name::For::Namespace::Finally;
Shorter::TheClassName foo;
Shorter::AnotherClassName bar;

55

हर लोगों को यह बताने के लिए मत सुनो कि नाम स्थान केवल नाम-स्थान हैं।

वे महत्वपूर्ण हैं क्योंकि उन्हें इंटरफ़ेस सिद्धांत को लागू करने के लिए कंपाइलर द्वारा माना जाता है। मूल रूप से, इसे एक उदाहरण द्वारा समझाया जा सकता है:

namespace ns {

class A
{
};

void print(A a)
{
}

}

यदि आप A ऑब्जेक्ट प्रिंट करना चाहते हैं, तो कोड यह होगा:

ns::A a;
print(a);

ध्यान दें कि हमने फ़ंक्शन को कॉल करते समय स्पष्ट रूप से नामस्थान का उल्लेख नहीं किया था। यह इंटरफ़ेस सिद्धांत है: C ++ एक फ़ंक्शन को उस प्रकार के लिए इंटरफ़ेस का हिस्सा होने के रूप में एक तर्क के रूप में लेता है, इसलिए नाम स्थान निर्दिष्ट करने की कोई आवश्यकता नहीं है क्योंकि पैरामीटर पहले से ही नाम स्थान को निहित करता है।

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

namespace ns {

class A
{
};

}

void print(A a)
{
}

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

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

और इसीलिए आपको C ++ के नामस्थान को "इंटरफ़ेस" समझना चाहिए जब आप एक का उपयोग करते हैं और इंटरफ़ेस सिद्धांत को ध्यान में रखते हैं।

यदि आप इस व्यवहार का बेहतर विवरण चाहते हैं, तो आप हर्ब सटर से पुस्तक असाधारण C ++ का उल्लेख कर सकते हैं


23
आपको वास्तव में हर कॉल को प्रिंट करने के लिए बदलना होगा () यदि ns: प्रिंट जोड़ा गया है, लेकिन कंपाइलर प्रत्येक कॉल को अस्पष्ट बताएगा। चुपचाप नए समारोह में जाना एक भयानक विचार होगा।
ग्रहण

मैं अब सोच रहा था, कि @Vincent ने क्या कहा है कि आपको प्रिंट करने के लिए सभी कॉल को बदलना होगा, यदि ऑटोरेंस प्रदान करेगा ns: प्रिंट () फ़ंक्शन, तो आप क्या कहना चाह रहे थे? जब लेखक ने एक ns :: Print () फ़ंक्शन जोड़ा है, तो आप अपना स्वयं का कार्यान्वयन निकाल सकते हैं? या कि आप ns :: प्रिंट () का उपयोग करके घोषणा को जोड़ते हैं? या फिर हावी है? धन्यवाद
Vaska El Gato

36

बड़ी सी ++ परियोजनाओं को मैंने शायद ही एक से अधिक नामस्थान (जैसे बूस्ट लाइब्रेरी) का उपयोग किया है।

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

व्यक्तिगत रूप से मुझे लगता है कि एक कोड-बेस जितना बड़ा हो जाता है, उतना ही महत्वपूर्ण नाम स्थान बन जाता है, यहां तक ​​कि एक भी एप्लिकेशन (या लाइब्रेरी) के भीतर भी। काम पर हम अपने आवेदन के प्रत्येक मॉड्यूल को अपने नामस्थान में डालते हैं।

नामस्थानों का एक और उपयोग (जिसका कोई उद्देश्य नहीं है) जिसका मैं बहुत अधिक उपयोग करता हूं वह अनाम नामस्थान है:

namespace {
  const int CONSTANT = 42;
}

यह मूल रूप से समान है:

static const int CONSTANT = 42;

हालांकि, अनाम नाम स्थान (स्थिर के बजाय) का उपयोग करना कोड और डेटा के लिए अनुशंसित तरीका है जो केवल C ++ में वर्तमान संकलन इकाई के भीतर दिखाई दे सकता है।


13
आपके दोनों उदाहरण समतुल्य हैं, const int CONSTANT = 42;क्योंकि किसी नेमस्पेस स्कोप में टॉप-लेवल कॉन्स का मतलब पहले से ही आंतरिक लिंकेज है। इसलिए आपको इस मामले में अनाम नामस्थान की आवश्यकता नहीं है।
सेलिबिट्ज़

19

इसके अलावा, ध्यान दें कि आप एक नामस्थान में जोड़ सकते हैं। यह एक उदाहरण के साथ स्पष्ट है, मेरा मतलब है कि आपके पास क्या हो सकता है:

namespace MyNamespace
{
    double square(double x) { return x * x; }
}

एक फ़ाइल में square.h, और

namespace MyNamespace
{
    double cube(double x) { return x * x * x; }
}

एक फाइल में cube.h। यह एक सिंगल नेमस्पेस को परिभाषित करता है MyNamespace(यानी, आप कई फाइलों में एक सिंगल नेमस्पेस को परिभाषित कर सकते हैं)।


11

जावा में:

package somepackage;
class SomeClass {}

C ++ में:

namespace somenamespace {
    class SomeClass {}
}

और उनका उपयोग करते हुए, जावा:

import somepackage;

और सी ++:

using namespace somenamespace;

इसके अलावा, पूर्ण नाम जावा के लिए "somepackge.SomeClass" और C ++ के लिए "somenamespace :: SomeClass" हैं। उन सम्मेलनों का उपयोग करके, आप जावा में उपयोग किए जाने वाले नामों की तरह व्यवस्थित कर सकते हैं, जिसमें नामस्थान के लिए फ़ोल्डर नाम मिलान करना भी शामिल है। फ़ोल्डर-> पैकेज और फ़ाइल-> वर्ग की आवश्यकताएं हालांकि नहीं हैं, इसलिए आप अपने फ़ोल्डर्स और कक्षाओं को स्वतंत्र रूप से पैकेज और नामस्थान से दूर कर सकते हैं।


6

@ मर्ज़

हां, आप एक समय में कई नामस्थानों का उपयोग कर सकते हैं, जैसे:

using namespace boost;   
using namespace std;  

shared_ptr<int> p(new int(1));   // shared_ptr belongs to boost   
cout << "cout belongs to std::" << endl;   // cout and endl are in std

[फ़रवरी 2014 - (क्या यह वास्तव में इतना लंबा है?): यह विशेष उदाहरण अब अस्पष्ट है, जैसा कि जॉय नीचे बताते हैं। बूस्ट और एसटी :: अब प्रत्येक के पास एक शेयर्ड_प्ट्र है।]


2
ध्यान दें कि अब तक stdभी है shared_ptr, इसलिए जब आप उपयोग करने का प्रयास करते हैं तो नाम boostऔर stdनाम दोनों का उपयोग करना बंद हो जाएगा shared_ptr
जॉय

2
यह एक अच्छा उदाहरण है कि क्यों कई सॉफ्टवेयर हाउस इस तरह से पूरे नामस्थानों को आयात करने को हतोत्साहित करेंगे। यह हमेशा नाम स्थान निर्दिष्ट करने के लिए चोट नहीं करता है, और यदि वे बहुत लंबे हैं तो नाम से एक उपनाम या केवल महत्वपूर्ण विशिष्ट कक्षाएं बना रहे हैं।
धान

5

आप उदाहरण के लिए किसी फ़ंक्शन के अंदर "नाम स्थान का उपयोग कर ..." भी शामिल कर सकते हैं:

void test(const std::string& s) {
    using namespace std;
    cout << s;
}

3

आम तौर पर बोलते हुए, मैं कोड के एक निकाय के लिए एक नाम स्थान बनाता हूं अगर मुझे लगता है कि संभवतः अन्य पुस्तकालयों के साथ फ़ंक्शन या प्रकार नाम विरोध हो सकता है। यह ब्रांड कोड, अला बूस्ट :: के लिए भी मदद करता है ।


3

मैं घटकों के लिए अनुप्रयोग और उप नामस्थान के लिए एक शीर्ष-स्तरीय नाम स्थान का उपयोग करना पसंद करता हूं।

जिस तरह से आप अन्य नामस्थानों से कक्षाओं का उपयोग कर सकते हैं वह आश्चर्यजनक रूप से जावा के तरीके के समान है। आप या तो "उपयोग NAMESPACE" का उपयोग कर सकते हैं जो "आयात पैकेज" कथन के समान है, उदाहरण के लिए std का उपयोग करें। या आप पैकेज को "::" के साथ अलग किए गए वर्ग के उपसर्ग के रूप में निर्दिष्ट करते हैं, उदाहरण के लिए std :: string। यह जावा में "java.lang.String" के समान है।


3

ध्यान दें कि वास्तव में C ++ में एक नाम स्थान केवल एक नाम स्थान है। वे किसी भी एनकैप्सुलेशन को प्रदान नहीं करते हैं जो पैकेज जावा में करते हैं, इसलिए आप शायद उनका उतना उपयोग नहीं करेंगे।


2

मैंने C ++ नाम का उपयोग उसी तरह किया है जैसे मैं C #, पर्ल, आदि में करता हूं। यह सिर्फ मानक लाइब्रेरी सामान, थर्ड पार्टी सामान और मेरे अपने कोड के बीच प्रतीकों का एक अर्थपूर्ण अलगाव है। मैं अपना खुद का ऐप एक नेमस्पेस में रखूंगा, फिर अलग करने के लिए दूसरे नामस्थान में एक पुन: प्रयोज्य लाइब्रेरी घटक।


2

जावा और सी ++ के बीच एक और अंतर यह है कि सी ++ में, नेमस्पेस पदानुक्रम को फाइल सिस्टम लेआउट को बनाने की आवश्यकता नहीं है। इसलिए मैं एक एकल नाम स्थान में एक पूरी पुन: प्रयोज्य पुस्तकालय, और उप-श्रेणियों में पुस्तकालय के भीतर सबसिस्टम रखने की प्रवृत्ति रखता हूं:

#include "lib/module1.h"
#include "lib/module2.h"

lib::class1 *v = new lib::class1();

यदि नाम विरोधाभास की संभावना थी, तो मैं केवल उप-नक्षत्रों को नेस्टेड नेमस्पेस में रखूंगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.