2009-07-29 12 views
5

तरह से मैं एक अंतरफलक वर्ग के लिए इसी तरह की है:बेस्ट एक सी का उपयोग करने के ++ इंटरफ़ेस

class IInterface 
{ 
public: 

    virtual ~IInterface() {} 

    virtual methodA() = 0; 

    virtual methodB() = 0; 

}; 

मैं तो इंटरफ़ेस को लागू:

class AImplementation : public IInterface 
{ 
    // etc... implementation here 
} 

जब मैं एक आवेदन पत्र में इंटरफ़ेस का उपयोग यह है करने के लिए बेहतर कंक्रीट क्लास एमिमेंटेशन का एक उदाहरण बनाएं। उदाहरण के लिए।

class IInterface 
{ 
public: 

    virtual ~IInterface() {} 

    static std::tr1::shared_ptr<IInterface> create(); // implementation in .cpp 
    virtual methodA() = 0; 

    virtual methodB() = 0; 

}; 

तो मैं तो जैसे मुख्य में इंटरफेस का उपयोग करने में सक्षम हो जाएगा:

int main() 
{ 
    AImplementation* ai = new AIImplementation(); 
} 

या यह बेहतर तरह निम्नलिखित इंटरफ़ेस में सदस्य समारोह "बनाने के" एक कारखाने लगाने के लिए है

int main() 
{ 
    std::tr1::shared_ptr<IInterface> test(IInterface::create()); 
} 

पहला विकल्प सामान्य प्रथा प्रतीत होता है (इसका अधिकार नहीं कहना)। हालांकि, दूसरा विकल्प "प्रभावी सी ++" से प्राप्त किया गया था।

+0

भाषा की शुद्धता के लिए बस कुछ नोट: सी ++ में कोई तरीका नहीं है, सदस्य कार्य हैं। – Artyom

+1

मैं इस तरह मुख्य() लिखूंगा: 'int मुख्य() { IInterface * i = नया एमिलीमेंटेशन(); } ' –

उत्तर

8

इंटरफ़ेस का उपयोग करने के सबसे आम कारणों में से एक यह है कि आप "एक अमूर्तता के खिलाफ प्रोग्राम" बल्कि एक ठोस कार्यान्वयन कर सकते हैं।

इसका सबसे बड़ा लाभ यह है कि यह आपके कोड के कुछ हिस्सों को बदलने की अनुमति देता है जबकि शेष कोड पर परिवर्तन को कम करता है।

इसलिए हालांकि हम जो भी बना रहे हैं उसकी पूरी पृष्ठभूमि नहीं जानते हैं, मैं इंटरफ़ेस/फैक्ट्री दृष्टिकोण के लिए जाऊंगा।

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

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

+0

धन्यवाद ऐश। मैं इस समाधान के साथ आगे बढ़ गया क्योंकि यह घोषणा और definitioin के बीच एक स्पष्ट रेखा प्रदान करता है। और इसके लिए इंटरफ़ेस का उपयोग करते समय मुझे केवल इंटरफ़ेस हेडर फ़ाइल को शामिल करने की आवश्यकता है, न कि हेडर फ़ाइल में कार्यान्वयन भी शामिल है। – Seth

1

किस अर्थ में "बेहतर"?

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

लेकिन यदि कई ठोस वर्ग हो सकते हैं, और यदि आप बेस क्लास को कसकर उनके साथ जोड़ना नहीं चाहते हैं, तो कारखाना पैटर्न उपयोगी हो सकता है।

और हाँ, यह युग्मन को कम करने में मदद कर सकता है - यदि आधार वर्ग व्युत्पन्न कक्षाओं के लिए आधार वर्ग के साथ स्वयं को पंजीकृत करने के लिए कुछ साधन प्रदान करता है। यह फैक्ट्री को यह जानने की अनुमति देगा कि कौन सी व्युत्पन्न कक्षाएं मौजूद हैं, और उन्हें कैसे बनाएं, उनके बारे में संकलन-समय की जानकारी के बिना।

+0

मैं वास्तव में COM का उपयोग कर रहा हूँ। मेरे पास एक वीसीएल जीयूआई है और मुझे विंडोज एक्सप्लोरर से ड्रैग और ड्रॉप करने की जरूरत है।इसलिए मैं अपने इंटरफ़ेस में आईडीप्रोटाइजेशन प्राप्त कर रहा हूं, और मुझे ऐसे घटक मिल रहे हैं जो इस इंटरफ़ेस के माध्यम से अपने हैंडल को पंजीकृत करने के लिए एप्लिकेशन में ड्रॉप लक्ष्य बनना चाहते हैं। तो शायद यह फैक्ट्री विधि का उपयोग करने के लायक नहीं होगा, और उपरोक्त मिशेल सफ्यान के सुझाव का उपयोग करने के लिए बेहतर होगा। – Seth

0

मैं पहले विकल्प के साथ जाऊंगा क्योंकि यह अधिक आम और अधिक समझ में आता है। यह वास्तव में आपके ऊपर है, लेकिन यदि आप एक वाणिज्यिक ऐप पर काम करते हैं तो मैं पूछूंगा कि मेरे साथियों का क्या उपयोग होता है।

4

अभी तक एक और विकल्प है जो आप का उल्लेख नहीं किया है नहीं है:

 
int main(int argc, char* argv[]) 
{ 
    //... 
    boost::shared_ptr<IInterface> test(new AImplementation); 
    //... 
    return 0; 
} 

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

+2

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

2

आपके प्रश्न में दो अलग-अलग मुद्दे हैं: 1. निर्मित ऑब्जेक्ट का संग्रहण कैसे प्रबंधित करें। 2. ऑब्जेक्ट कैसे बनाएं।

भाग 1 सरल है - आपको स्मार्ट पॉइंटर जैसे std :: tr1 :: shared_ptr का उपयोग करना चाहिए ताकि स्मृति लीक को रोकने के लिए अन्यथा फैंसी प्रयास/पकड़ तर्क की आवश्यकता हो।

भाग 2 अधिक जटिल है।

आप मुख्य() में केवल() लिखना नहीं चाहते हैं जैसे कि आप चाहते हैं - आपको IInterface :: create() लिखना होगा, अन्यथा संकलक एक वैश्विक फ़ंक्शन की तलाश करेगा जिसे बनाएं, जिसे बनाया गया है, जिसे वह नहीं है जो आप चाहते हैं। ऐसा लगता है कि 'std :: tr1 :: shared_ptr test' को प्रारंभ() द्वारा बनाए गए मान के साथ आरंभ किया जा सकता है, ऐसा लगता है कि यह वही होगा जो आप चाहते हैं, लेकिन ऐसा नहीं है कि सी ++ कंपाइलर कैसे काम करते हैं।

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

1

पहली विधि का उपयोग करें। दूसरे विकल्प में आपकी फैक्ट्री विधि को प्रति-ठोस वर्ग लागू करना होगा और इंटरफ़ेस में ऐसा करना संभव नहीं है। आईई, IInterface :: create() को पता नहीं है कि वास्तव में आप किस ठोस वर्ग को तुरंत चालू करना चाहते हैं।

एक स्थिर विधि वर्चुअल नहीं हो सकती है, और आपके ठोस वर्गों में एक गैर स्थैतिक निर्माण() विधि को लागू करने से वास्तव में आपको इस मामले में कुछ भी नहीं मिला है।

फैक्टरी विधियां निश्चित रूप से उपयोगी हैं, लेकिन यह सही उपयोग नहीं है।

प्रभावी सी ++ में कौन सा आइटम दूसरे विकल्प की सिफारिश करता है? मैं इसे अपने में नहीं देखता (हालांकि मेरे पास दूसरी पुस्तक भी नहीं है)। यह एक गलत समझ को दूर कर सकता है।

क्या आप वाकई एक सूचक का उपयोग करना चाहते हैं:

+1

आइटम 31, मेरे पास तीसरा संस्करण – Seth

+0

है मेरे पास मेरा प्रभावी सी ++ आसान नहीं है, लेकिन मुझे लगता है कि ओपी सार फैक्टरी पैटर्न का जिक्र कर रहा है (जिसे मैंने हमेशा ओवरकिल के रूप में सोचा था, लेकिन हो सकता है कि यह उचित हो।) इस बात के लिए कि कारखाने को प्रत्येक ठोस वर्ग के लिए लागू करने की आवश्यकता है या नहीं: आपके पास एक सार्वजनिक फैक्ट्री विधि होगी, जो ठोस उदाहरण बनाने के लिए गैर-सार्वजनिक स्थैतिक तरीकों का आह्वान करती है। व्युत्पन्न कक्षाएं खुद को निर्माण के लिए उपलब्ध कराने के लिए कारखाने के साथ पंजीकृत हैं। फैक्ट्री कैसे चुनता है ** जो ** किसी दिए गए समय पर बनाने के लिए कक्षा व्युत्पन्न है कार्यान्वयन-विशिष्ट है। –

+0

लेकिन आप निर्माण() विधि के बारे में सही हैं। पुस्तक में यह वास्तव में परीक्षण है (IInterface :: create()) – Seth

0

मैं वहाँ एक बहुत ही सरल सवाल है?

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

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