2011-12-20 17 views
5

ईमानदारी से कहूं तो मैं सच में नहीं पता है, कैसे इस सवाल पूछने के लिए है, इसलिए कृपया नहीं पागल वैसे भी हो :)सी ++ माता पिता वापसी बच्चे में समारोह

, मैं mutators (setters) करना चाहते हैं मेरी कक्षा में this लौटने के लिए jQuery- a.name("something").address("somethingelse"); की अनुमति देने के लिए मेरे पास एक मूल वर्ग (Entity) और कई बाल-प्लेस (Client, Agent etc.) हैं। अधिकांश चीजों के लिए म्यूटेटर Entity वर्ग (जैसे नाम या पता) से विरासत में प्राप्त होते हैं, लेकिन वे Entity ऑब्जेक्ट लौटाते हैं, इसलिए मैं उन पर क्लाइंट म्यूटेटर को कॉल नहीं कर सकता।

दूसरे शब्दों में:

// name mutator 
Entity& Entity::name(const string& name) { 
    // [...] checks 
    _name = name; 
    return *this; 
} 

// budgetRange mutator 
Client& Client::budgetRange(const long int& range) { 
    // [...] checks 
    _budgetRange = range; 
    return *this; 
} 

फिर जब मैं इसे कहते हैं:

Client a; a.name("Dorota Adamczyk").budgetRange(50); 

संकलक (तार्किक) का कहना है, इकाई वस्तु नहीं budgetRange सदस्य वाले (क्योंकि नाम एक इकाई देता है, ग्राहक नहीं)।

मेरा प्रश्न अब है: मैं इस तरह कुछ कैसे कार्यान्वित कर सकता हूं? मैं childclasses में सभी इकाई कार्यों अधिक भार के बारे में सोचा, लेकिन वह अच्छा नहीं होगा और विरासत :)

अपने विचारों के लिए अग्रिम रूप से धन्यवाद करने के विचार के खिलाफ होगा: डी

+0

Google 'विधि chaining' और' नाम पैरामीटर idiom' के लिए भी Google, जो आप कर रहे हैं।ध्यान दें कि, जब 'क्लाइंट' से विरासत प्राप्त होता है तो आपका कोड नीचे सीआरटीपी समाधान का उपयोग करके फिर से टूट जाएगा। – cheind

उत्तर

7

आपको CRTP का उपयोग करना चाहिए।

template<class Derived> 
class Entity 
{ 
    Derived* This() { return static_cast<Derived*>(this); } 

public: 
    Derived& name(const string& name) 
    { 
     ... 
     return *This(); 
    } 
}; 

class Client : public Entity<Client> 
{ 
public: 
    Client& budgetRange(const long& range) 
    { 
     ...  
     return *this; 
    } 
}; 

आप वर्चुअल कार्यों का उपयोग करना चाहते हैं, तो आप भी सार आधार वर्ग, जोड़ सकते हैं इस तरह:

class AbstractEntity 
{ 
public: 
    virtual void foo() = 0; 

    virtual ~AbstractEntity(); 
}; 

template<class Derived> 
class Entity : AbstractEntity 
{...}; 
+0

मुझे वास्तव में यह विचार पसंद है (विशेष रूप से यह() फ़ंक्शन ^^)। बहुत बहुत धन्यवाद, यही वह है जो मैं ढूंढ रहा था :) – Asmodiel

+0

उत्कृष्ट सामान। मैं सीआरटीपी का एक अच्छा उदाहरण खोज रहा हूं। धन्यवाद। – sje397

+0

@ sje397 सीआरटीपी का एक और अच्छा उदाहरण एक सामान्य पेड़ वर्ग है, जो 'टेम्पलेट कक्षा नोड' के माध्यम से ठोस नोड कार्यान्वयन प्रदान करता है। उदाहरण के लिए: 'डी और नोड :: बाएं()' कंक्रीट नोड इम्प्लायर प्रदान कर सकता है। इस तरह आप सामान्य पेड़ तर्क को जेनेरिक नोड वर्ग में भर सकते हैं। – cheind

3

"दिलचस्प पुनरावर्ती टेम्पलेट "पैटर्न यहां मदद कर सकता है; , आधार वर्ग एक टेम्पलेट, व्युत्पन्न वर्ग द्वारा parametrised बनाने की तर्ज पर:

template <typename Derived> 
struct Entity { 
    Derived & name(std::string const & name) { 
     // stuff 
     return static_cast<Derived&>(*this); 
    } 
}; 

struct Client : Entity<Client> { 
    Client & budget(long range) { 
     // stuff 
     return *this; 
    } 
}; 

Client().name("Mike").budget(50); // should compile 

यह तभी अपने सभी प्रकार के Entity से सीधे वारिस काम करेंगे। यदि आपको पॉलिमॉर्फिक होने के प्रकार की आवश्यकता है (यानी सभी एक सामान्य बेस क्लास साझा करते हैं), तो आपको एक और गैर-टेम्पलेट बेस क्लास जोड़ने की आवश्यकता होगी, और Entity उस से प्राप्त होगा।

+0

आपके उत्तर के लिए बहुत बहुत धन्यवाद, लेकिन मैं अबिक्स का चयन करूंगा क्योंकि इसमें यह शामिल है() विचार :) हालांकि उपरोक्त है। – Asmodiel

2

अब जब कि लगभग सब कुछ पहले से ही कहा गया है, मैं जवाब का एक टुकड़ा जोड़ना चाहते हैं कि एक विरासत के कई स्तरों से अधिक CRTP उपयोग करने के लिए अनुमति देता है:

ऊपर CRTP कार्यान्वयन तोड़ जब एक, Client से इनहेरिट करना के बाद से DerivedClient संदर्भित करेंगे चाहता है। मामले में आप CRTP पद्धति का उपयोग कर विरासत के कई स्तरों से अधिक नामित पैरामीटर मुहावरा ले जाने के लिए सक्षम होना चाहते हैं, तो आप Client_T की एक टेम्पलेट नि: शुल्क संस्करण

जोड़ने उपयोगकर्ता प्रदान करने के लिए इतना

template<class Derived> 
class Entity_T 
{ 
protected: 
    Derived* This() { return static_cast<Derived*>(this); } 
public: 
    Derived& name(const string& name) 
    { 
     ... 
     return *This(); 
    } 
}; 

template<class Derived> 
class Client_T : public Entity_T<Derived> 
{ 
    Derived& budgetRange(const long& range) 
    { 
     ...  
     return *This(); 
    } 
}; 

की तरह अपनी कक्षाओं कोड करने के लिए की जरूरत है

class Client : public Client_T<Client> {}; 

चाहे यह विस्तारित कोड आधार के लायक है या नहीं, पूरी तरह से आपके ऊपर है। ध्यान दें, मैंने ऊपर दिए गए कोड को संकलित नहीं किया है।

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