2012-01-26 13 views
8

संपादित करें: मैं सी ++ के साथ काम कर रहा हूँ।सबसे खूबसूरत तरीका के आसपास इस बहुरूपता अंक प्राप्त करने

तो, मैं तरीकों/कार्य बनाने रहा आकृतियों के बीच चौराहे परीक्षण करने के लिए।

class Shape {}; 

class Rectangle : public Shape {}; 

class Circle : public Shape {}; 

class Line : public Shape {}; 

अब मैं सबसे अच्छा तरीका चौराहे परीक्षण करने के लिए वास्तविक तरीकों/कार्य लिखने के लिए फैसला करने की जरूरत है,: मैं अनिवार्य रूप से यह किया है। लेकिन मेरे सभी आकृति आकार संकेत की एक सूची में संग्रहीत किया जाएगा, तो मैं मूल रूप की एक विधि/समारोह बुला कर दिया जाएगा:

bool intersects (Shape* a, Shape* b); 

उस बिंदु पर, मैं यह निर्धारित करने की जरूरत है जो आकार 'एक' के प्रकार और 'बी' हैं, इसलिए मैं टकराव का सही ढंग से पता लगा सकता हूं। मैं आसानी से, उनमें से एक कर सकते हैं बस कुछ आभासी तरीकों का उपयोग करके:

कि आकार में से एक निर्धारित करेंगे ('एक' अब है 'इस')। हालांकि, मुझे अभी भी 'बी' के प्रकार की आवश्यकता होगी। स्पष्ट समाधान आकार को 'आईडी' चर देने के लिए आकार देने के लिए है, और फिर उन लोगों के माध्यम से 'स्विच' करें, और फिर गतिशील_कास्ट का उपयोग करें। हालांकि, यह बहुत ही सुरुचिपूर्ण नहीं है, और ऐसा लगता है कि ऐसा करने के लिए एक और ओओ तरीका होना चाहिए।

कोई सुझाव?

+7

यह क्लासिक समस्या है जिसे डबल-प्रेषण द्वारा हल किया जाता है। – Mankarse

+0

हालांकि मेरी मूल खोज कभी-कभी डबल-प्रेषण के साथ दिखाई नहीं दे रही है, लेकिन मैं देखता हूं कि यह मेरी समस्या का समाधान कैसे करता है। धन्यवाद। संपादित करें: मैं इसे अप-वोट दूंगा, लेकिन मुझे यकीन नहीं है कि मेरे पास पर्याप्त प्रतिष्ठा नहीं है, या मुझे अप-वोट बटन नहीं मिल रहा है। –

उत्तर

7

@Mandarse के रूप में कहे अनुसार, इस विशिष्ट डबल प्रेषण मुद्दा है। ऑब्जेक्ट ओरिएंटेड भाषाओं में, या सी ++ भाषाओं कि ऑब्जेक्ट ओरिएंटेड अवधारणाओं को लागू कर सकते की तरह, यह आमतौर पर Visitor पैटर्न का उपयोग कर हल किया है।

Visitor इंटरफ़ेस ही सामान्य रूप में, ठोस प्रकार प्रति एक कॉलबैक परिभाषित करता है।

class Circle; 
class Rectangle; 
class Square; 

class Visitor { 
public: 
    virtual void visit(Circle const& c) = 0; 
    virtual void visit(Rectangle const& r) = 0; 
    virtual void visit(Square const& s) = 0; 
}; 

फिर, Shape पदानुक्रम इस के लिए अनुकूलित किया गया है। हमें दो तरीकों की आवश्यकता है: किसी भी प्रकार के आगंतुक को स्वीकार करने के लिए, दूसरा "उचित" चौराहे आगंतुक बनाने के लिए।

class Visitor; 
class Intersecter; 

class Shape { 
public: 
    virtual void accept(Visitor&) const = 0; // generic 
    virtual Intersecter* intersecter() const = 0; 
}; 

intersecter सरल है:

#include "project/Visitor.hpp" 

class Intersecter: public Visitor { 
public: 
    Intersecter(): result(false) {} 
    bool result; 
}; 

उदाहरण के लिए, सर्किल के लिए यह दे देंगे:

#include "project/Intersecter.hpp" 
#include "project/Shape.hpp" 

class Circle; 

class CircleIntersecter: public Intersecter { 
public: 
    explicit CircleIntersecter(Circle const& c): _left(c) {} 

    virtual void visit(Circle const& c); // left is Circle, right is Circle 
    virtual void visit(Rectangle const& r); // left is Circle, right is Rectangle 
    virtual void visit(Square const& s); // left is Circle, right is Square 

private: 
    Circle const& _left; 
}; // class CircleIntersecter 


class Circle: public Shape { 
public: 
    virtual void accept(Visitor& v) const { v.visit(*this); } 

    virtual CircleIntersecter* intersecter() const { 
    return new CircleIntersecter(*this); 
    } 
}; 

और उपयोग:

#include "project/Intersecter.hpp" 
#include "project/Shape.hpp" 

bool intersects(Shape const& left, Shape const& right) { 
    boost::scope_ptr<Intersecter> intersecter(left.intersecter()); 
    right.accept(*intersecter); 
    return intersecter->result; 
}; 

अन्य तरीकों की जरूरत है एक डबल डिस्पैच तंत्र, फिर ए आपको एक और "इंटरसेक्टर-जैसी" कक्षा बनाना है जो Visitor से परिणाम और विरासत को लपेटता है और Shape में रूट की गई एक नई "फैक्टरी" विधि है जो उचित संचालन प्रदान करने के लिए व्युत्पन्न कक्षाओं द्वारा ओवरराइड किया जाता है। यह थोड़ा लंबा हवादार है, लेकिन काम करता है।

नोट: एक ही परिणाम प्राप्त करने के लिए intersect(circle, rectangle) और intersect(rectangle, circle) को छोड़कर उचित है। आप कोड को कुछ तरीकों से कारक कर सकते हैं और कंक्रीट कार्यान्वयन के लिए CircleIntersecter::visit प्रतिनिधि हैं। यह कोड डुप्लिकेशन से बचें।

+0

घुसपैठिए के लिए परिभाषित नियंत्रक के पास कोई तर्क नहीं है और बाद में आप इसे तर्क के साथ कहते हैं। क्यूं कर? – user1754322

+0

@ user1754322: मैं कॉल नहीं कर सका, वास्तव में ऐसा लगता है कि मैं वास्तव में इसे बिल्कुल नहीं कहता हूं। क्या आप 'boost :: scoped_ptr intersecter (left.intersecter()) द्वारा उलझन में थे; 'जहां मैं एक * चर * नाम' intersecter' बना सकता हूं? –

+0

मैंने सोचा था कि 'boost :: scoped_ptr इंटर्सेक्टर (left.intersecter());' कुछ ऐसा था जैसे 'इंटरसेक्टर इंटरसेक्टर (बाएं।चौराहे()); है ना? – user1754322

4

आंद्रेई Alexandrescu अपने क्लासिक Modern C++ Design में इस समस्या को विस्तृत जानकारी दी। साथी पुस्तकालय लोकी में the implementation for Multi-Methods शामिल है।

अद्यतन

लोकी मल्टी तरीके की तीन कार्यान्वयन, उपयोगकर्ता की जरूरतों के आधार पर प्रदान करता है। कुछ सादगी के लिए हैं, कुछ गति के लिए हैं, कुछ कम युग्मन के लिए अच्छे हैं और कुछ दूसरों की तुलना में अधिक सुरक्षा प्रदान करते हैं। पुस्तक में अध्याय लगभग 40 पृष्ठों तक फैला है, और यह मानता है कि पाठक पुस्तक की कई अवधारणाओं से परिचित है - यदि आप बढ़ावा देने में सहज हैं, तो लोकी आपकी गली नीचे हो सकती है। मैं वास्तव में एसओ के लिए स्वीकार्य उत्तर को आसवित नहीं कर सकता, लेकिन मैंने आपको सी ++ के विषय के सर्वोत्तम स्पष्टीकरण की ओर इशारा किया है जो मुझे पता है।

+1

@anon_downvoter जब तक कि आप अपनी कार्रवाई को औचित्य न दें, इससे ज्यादा मदद नहीं मिलती है। – justin

+0

शायद कोड की कमी? वैसे भी हाँ, बहु-तरीकों सहायक होगा। –

+0

@MatthieuM। शायद। मैंने अपना जवाब विस्तारित करने के लिए विस्तारित किया है कि मैंने उदाहरण क्यों नहीं दिया। धन्यवाद। – justin

1

आप उदाहरण के लिए प्रत्येक Shape

करने के लिए एक क्षेत्र shapeType जोड़ सकते हैं:

class Shape { 
    virtual shapetype_t getShapeType() const; 
    // ... 
} 
2

सी ++ रन-टाइम पॉलीमोर्फिज्म में एक एकल प्रेषण (बेस क्लास vtable) है।

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

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

लेकिन उनमें से कुछ को कोड लेखन में अन्य लागत और कोड रखरखाव में अन्य लागत अधिक है। आपके पास अपने मामले में अनुमान लगाने का सबसे अधिक संभावना है कि व्यापार-बंद क्या है। कितने अन्य कक्षाएं आपको लगता है कि आपको भविष्य में जोड़ने की आवश्यकता हो सकती है?

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

  • कोई संबंधित समस्या नहीं^_^