2010-06-21 8 views
11

के लिए रिटर्न-टाइप पॉलीमोर्फिज्म मुझे यकीन नहीं है कि प्रश्न शीर्षक सटीक है ... मुझे अपना मूल सरल परिदृश्य समझाकर शुरू करें, और फिर मुझे यह बताने के लिए आगे बढ़ें कि मैं क्या करना चाहूंगा, लेकिन नहीं कर सकतापास-बाय-वैल्यू

class Operand; 

Operand genOperandA() { ...; return Operand(); } 
Operand genOperandB() { ...; return Operand(); } 
... // more operand-generation functions 

typedef Operand (*OpGen)(); 

// Table of function pointers 
static const OpGen generators[] = 
{ 
    genOperandA, 
    genOperandB, 
    ... 
}; 

// Function to do some operation on the operand 
void operate(Operand& op); 

... 

// Example call 
operate(generators[1]()); 

अब तक तो अच्छा (मुझे लगता है कि):

मूल रूप से, मैं की तरह कुछ था। हालांकि, अब कई व्युत्पन्न ऑपरेंड प्रकार हैं, उदा। class RegisterOperand : public Operand। मेरे पास नया, समर्पित genOperand फ़ंक्शन है जो आदर्श रूप से व्युत्पन्न प्रकारों के उदाहरण लौटाएंगे। लेकिन मैं ऐसा नहीं कर सकते:

Operand genOperandC() { ...; return RegisterOperand(); } 

और मैं ऐसा नहीं कर सकते:

RegisterOperand genOperandC() { ...; return RegisterOperand(); } 

static const OpGen generators[] = 
{ 
    ... 
    genOperandC, 
}; 

हालांकि, मैं जानता हूँ कि अगर मैं संदर्भ या सूचक प्रकार वापस आना था इस काम करेगा, इसलिए केवल

Operand *genOperandC() { ...; return new RegisterOperand(); } 

जो अब स्पष्ट सफाई जो मूल रूप से आवश्यक नहीं था की आवश्यकता है: विकल्प मैं वर्तमान में है की तरह कुछ है।

कोई भी विकल्प जिस पर मैंने विचार नहीं किया है?

उत्तर

4

ऐसे अन्य डिज़ाइन हो सकते हैं जिनके लिए आपको पॉइंटर्स का उपयोग करने की आवश्यकता नहीं है, लेकिन यदि आपको आवश्यकता है या इस तरह से जाना चाहते हैं, तो इससे आपको रूचि हो सकती है।


तो एक सूचक लौटाते समय एक समस्या है, तो आप निश्चित रूप से वापसी प्रकार के रूप में स्मार्ट संकेत के उपयोग पर विचार करना चाहिए (जरूरत के लिए "सफाई" चीजों की वजह से)।

boost::shared_ptr<Operand> genOperandC() 
{ 
    return boost::shared_ptr<Operand>(new RegisterOperand()); 
} 

इस तरह, आप delete मैन्युअल कॉल करने के लिए नहीं होगा:

यहाँ स्मार्ट संकेत के साथ अपने कारखाने विधि का एक उदाहरण है यह आप के लिए boost::shared_ptr<Operand> का नाशक द्वारा किया जाएगा जरूरत पड़ने पर। कार्यों कास्टिंग

आप जिसके परिणामस्वरूप सूचक कास्ट करने के लिए की जरूरत है बाद में, boost प्रदान करता है और साथ ही:

boost::shared_ptr<Operand> op = genOperandC(); 

boost::shared_ptr<RegisterOperand> rop = 
    boost::dynamic_pointer_cast<RegisterOperand>(op); 
+1

साझा पॉइंटर स्वयं बनाने के बजाय 'boost :: make_shared' का उपयोग करें, यह एक साधारण रैपर विधि है लेकिन आवश्यक स्मृति आवंटन की संख्या को कम करें (और इस प्रकार तेज़ है) –

7

आप लपेट कर सकते हैं:

class Operand 
{ 
public: 

private: 
    std::unique_ptr<OperandImpl> mImpl; 
}; 

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

+0

क्या यह विचार यहां है कि मेरे अलग-अलग उपप्रकार वास्तव में प्राप्त होंगे 'OperandImpl', और उस सदस्य को 'ऑपरेंड' को कॉल किया जाना चाहिए, जिसे बस * * एमआईएमपीएल 'में सौंपा जाना चाहिए? –

+0

हां, यह एक क्लासिक रणनीति पैटर्न है जहां वास्तविक मेमोरी हैंडलिंग क्लाइंट से छिपी हुई है (एक पॉइंटर, स्मार्ट या नहीं, 'OperandImpl' पर लौटने की बजाय)। हालांकि आप प्रतिनिधि (तर्क, जांच आदि आदि की जांच करने से पहले कुछ काम कर सकते हैं ...) –

0

इस तरह कुछ कैसे?

ध्यान दें कि आप केवल संचालित नहीं कर सकते हैं (जनरेटर [i]()) मूल संचालन के रूप में() एक गैर-कॉन्स्ट संदर्भ लेते हैं।

#include <iostream> 
#include <string> 
#include <memory> 

class Operand { 
public: 
     Operand(std::string x = "Operand"): x(x) {} 
     const std::string x; 
}; 

class RegisterOperand: public Operand { 
public: 
     RegisterOperand(std::string x = "RegisterOperand") 
       : Operand(x) {} 
}; 

typedef std::auto_ptr<Operand> POperand; 

POperand genOperandA() { return POperand(new Operand("genOperandA")); } 
POperand genOperandB() { return POperand(new Operand("genOperandB")); } 
POperand genOperandC() { return POperand(new RegisterOperand()); } 
// more operand-generation functions 

typedef POperand (*OpGen)(); 

// Table of function pointers 
static const OpGen generators[] = 
{ 
     genOperandA, 
     genOperandB, 
     genOperandC, 
}; 

void operate(const POperand& op) 
{ 
     std::cout << op->x << std::endl; 
} 

int main() 
{ 
     operate(generators[0]()); 
     operate(generators[1]()); 
     operate(generators[2]()); 
     return 0; 
} 
+0

'auto_ptr' का उपयोग C++ 0x में बहिष्कृत किया गया है। इसके बजाए 'unique_ptr' का उपयोग करना पसंद करें। यदि आपके पास अभी तक C++ 0x तक पहुंच नहीं है, तो 'shared_ptr' को प्राथमिकता दें। –

+1

@Matthieu: जबकि मुझे unique_ptr बहुत पसंद है, मैं इसका उपयोग करने में संकोच करता हूं क्योंकि यह सी ++ 0x भाषा सुविधा पर निर्भर करता है। मुझे लगता है कि अगर आप जानते हैं कि आप क्या कर रहे हैं और share_ptr के संदर्भ-गिनती ओवरहेड नहीं चाहते हैं तो std :: auto_ptr का उपयोग करना ठीक है। बस मेरे 2 सेंट। – sellibitze

0

मैं अपने आप को पता है इस सवाल का कुछ समय के लिए कहा गया था पहले, लेकिन मैं हाल ही में इस समस्या से टकरा गई और मैं किसी अन्य समाधान है कि मैं हालांकि यहां उपयोगी हो सकता है के साथ आया था।

तो विचार सूचक को प्रबंधित करने के लिए एक रैपर बनाने के लिए है, लेकिन अद्वितीय सूचक के विपरीत रैपर की प्रतिलिपि बनाने का समर्थन करने के लिए जो केवल स्थानांतरित किया जा सकता है।

class PolymorphicType { 
public: 
    /* 
     Class interface ... 
    */ 
    PolymorphicType() { it = nullptr; } 
    virtual ~PolymorphicType() { if(it != nullptr) delete it; }   

    PolymorphicType& operator=(const PolymorphicType& org) { 
      //Clone the derived type and store it 
      if(org.it != nullptr) 
       it = org.it->clone(); 
    } 
private: 
    Base* it; 
}; 

प्रत्येक व्युत्पन्न वर्ग को अब अपनी क्लोन विधि लागू करनी होगी और आप जाने के लिए अच्छे हैं! और यदि यहां एक अच्छी पोस्ट है जो बताती है कि व्युत्पन्न प्रकारों का क्लोनिंग कैसे काम करता है: Copying derived entities using only base class pointers, (without exhaustive testing!) - C++

आशा है कि इससे किसी को मदद मिलेगी!