2010-05-08 19 views
6

मेरे पास कुछ फ़ंक्शन हैं जिन्हें एक साथ समूहीकृत किया जा सकता है, लेकिन कुछ ऑब्जेक्ट/इकाई से संबंधित नहीं हैं और इसलिए विधियों के रूप में नहीं माना जा सकता है।सी ++ नेमस्पेस और टेम्पलेट

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

नीचे कोड देखें (शायद नहीं सबसे अच्छा उदाहरण और एक अन्य कार्यक्रम वास्तुकला के साथ बेहतर किया जा सकता है, लेकिन मैं सिर्फ एक बेहतर नमूना नहीं सोच सकते हैं ...)

नमूना कोड (header)

namespace algorithm { 
    void HandleCollision(Object* object1, Object* object2); 
} 

नमूना कोड (cpp)

#include "header" 

// Anonymous namespace that wraps 
// routines that are used inside 'algorithm' methods 
// but don't have to be exposed 
namespace { 
    void RefractObject(Object* object1) { 
     // Do something with that object 
     // (...) 
    } 
} 

namespace algorithm { 
    void HandleCollision(Object* object1, Object* object2) { 
     if (...) RefractObject(object1); 
    } 
} 

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

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

मैं अपने इंटरफेस से RefractObject समारोह को छिपाना चाहते हैं, लेकिन मैं बस अपने घोषणा (सिर्फ इसलिए कि मैं एक header फ़ाइल में अपने सभी कोड है) केवल दृष्टिकोण मैं के साथ आया नहीं निकाल सकते ...

की तरह कुछ किया गया था:

नमूना कोड (header)

namespace algorithm { 
    // Is still exposed as a part of interface! 
    namespace impl { 
     template <typename T> 
     void RefractObject(T* object1) { 
     // Do something with that object 
     // (...) 
     } 
    } 

    template <typename T, typename Y> 
    void HandleCollision(T* object1, Y* object2) { 
     impl::RefractObject(object1); 
     // Another stuff 
    } 
} 

कोई भी विचार कैसे कोड डिजाइन के मामले में इस बेहतर बनाने के लिए?

उत्तर

7

यह एक बहुत ही आम समाधान है। बूस्ट करता है, और मैं इसे भी करता हूं, लेकिन इसके बजाय detail नामस्थान के साथ। बस इसे एक नियम बनाओ: "detail के अंदर न देखें!"

फ़ाइल के अनुसार, मैं अपनी फ़ाइल का विवरण देने की सलाह देता हूं, और इसे एक विस्तार फ़ोल्डर में टकराता हूं।

//   v 
#include "detail/RefractObject.hpp" 

namespace algorithm { 

    template <typename T, typename Y> 
    void HandleCollision(T* object1, Y* object2) { 
     detail::RefractObject(object1); 
     // Another stuff 
    } 
} 

यह सामान्य रूप में सिर्फ अच्छे कोड प्रथा है (चीजों को विभाजित करने और फिर से प्रयोग करने योग्य रखने के लिए) और कार्यान्वयन विवरण के हेडर फाइल क्लीनर रहता है: यह है, मेरे कोड के लिए समान होगा।

1

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

यह भी पूछना चाहिए कि क्यों अपवर्तक सदस्य विधि नहीं हो सकता है।

+0

क्या सदस्य? इसके अलावा, फ्री-फ़ंक्शंस को वैसे भी पसंद किया जाता है। :) – GManNickG

+0

ठीक है, मैंने कहा कि यह सिर्फ नमूना के लिए है। मेरे वास्तविक प्रोजेक्ट 'एल्गोरिदम' के मामले में सन्निकटन एल्गोरिदम और पथ-खोज एल्गोरिदम शामिल हैं, ताकि उन्हें उस शब्द के अर्थ में 'सदस्यों' बनाना असंभव हो ... –

+0

सदस्य कार्य> इंटेलिजेंस के आविष्कार के बाद से मुक्त कार्य। – Puppy

2

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

एक टेम्पलेट उदाहरण:,
1) आप पूरी क्लास टेम्पलेट कर सकते हैं सुनिश्चित करने के हर कार्य का संस्करण नहीं है कि हर type- आप कर सकते थे के लिए:

template<class T> 
class StringOperator 
{ 
friend SomeOtherLibraryClass; // Let it use "Hidden()" 
private: 
    StringOperator() {} 
    ~StringOperator() {} 
    StringOperator(const StringOperator&); 
    StringOperator& operator=(const StringOperator&); 

    static bool Hidden(const T& input) { 
     // Hidden routine end-users shouldn't see... 
    } 

public: 
    static void YourFunction(T& parameter) { 
     // Some public code.... 
    } 

    static T  AnotherRoutine(const T* ptr) { 
     // Some public code... 
    } 
}; 

यहाँ कुछ फायदे बनाम एक namespace हैं प्रकार के आधार पर कार्यों को जोड़ने/हटाने के लिए भी विशेषज्ञ।
2) आपके पास एक निजी क्षेत्र है जहां आप गैर-सार्वजनिक वस्तुओं और विधियों की घोषणाओं को छुपा सकते हैं जिन्हें आपको
3) "मित्र" तंत्र के माध्यम से, आप अन्य वस्तुओं को "SomeOtherLibraryClass" के बिना अपने कार्यों का उपयोग कर सकते हैं उन्हें उपयोगकर्ताओं को समाप्त करने के लिए उजागर।

अंतिम उपयोगकर्ता "स्ट्रिंगऑपरेटर :: फ़ंक्शननाम()" के साथ फ़ंक्शंस तक पहुंच सकते हैं, या आप "स्ट्रिंगऑपरेटर :: फ़ंक्शननाम()" प्रदान करने के बजाय फ़ंक्शंस को टेम्पलेट कर सकते हैं। उत्तरार्द्ध एक ही पैटर्न है जिसका उपयोग वे नामस्थान में कार्यों तक पहुंचने के लिए करेंगे।

0

मैंने थोड़ी देर के लिए एक ही चीज़ के बारे में सोचा। अंत में, मैंने कक्षाओं का उपयोग करने का फैसला किया ताकि कोड अधिक पोर्टेबल, पुन: प्रयोज्य और सामान्य हो।

  • कक्षाएं किसी को मेटा-प्रोग्रामिंग जैसे लक्षण, टैग प्रेषण और नीतियों के सभी प्रकार की अनुमति देती हैं।
  • कक्षाओं में पहले से ही सार्वजनिक, निजी और संरक्षित है।

केवल दो कारणों से आप नाम स्थान का प्रयोग करेंगे:

  • बनाम boost::for_each
  • नामकरण संघर्ष std::for_each हल करने दृश्य शोर को कम करने। उदाहरण के लिए using namespace boost::filesystem, आपको :: के बिना बस अपना फ़ंक्शन कॉल करने देगा।

भी इन दो मामलों के लिए, आप या तो वर्ग तरीकों है कि यह रूप में fs.mkdir()। प्लस के वारिस कर सकते हैं या (शुरू करके नाम बदलने my_own_filesystem_methods fs; और हमें, .:: तुलना में कम है।

वहाँ अन्य लाभ दिए गए हैं std::cout << "hi" << endl; जैसे नामस्थानों का यह बहुत महत्वपूर्ण नहीं है।

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