2012-01-03 11 views
8

में इंटरफेस को कार्यान्वित करना मैं आमतौर पर सी # में प्रोग्राम करता हूं लेकिन सी ++ का थोड़ा सा प्रयास करने की कोशिश कर रहा हूं और कुछ हद तक सी ++ में इंटरफेस को कार्यान्वित करने की कोशिश कर रहा हूं।सी ++

सी # में मैं कुछ इस तरह करते हैं:

class Base<T> 
{ 
    public void DoSomething(T value) 
    { 
     // Do something here 
    } 
} 

interface IDoubleDoSomething 
{ 
    void DoSomething(double value); 
} 

class Foo : Base<double>, IDoubleDoSomething 
{ 
} 

C++ में मैं इसे इस तरह से क्रियान्वित किया है:

template <class T> 
class Base 
{ 
public: 
    virtual void DoSomething(T value) 
    { 
     // Do something here 
    } 
}; 

class IDoubleDoSomething 
{ 
public: 
    virtual void DoSomething(double value) = 0; 
}; 

class Foo : public Base<double>, public IDoubleDoSomething 
{ 
}; 

समस्या यह है कि मैं फू का दृष्टांत नहीं कर सकते क्योंकि यह है अमूर्त (DoSomething लागू नहीं करता है)। मुझे एहसास है कि मैं DoSomething को कार्यान्वित कर सकता हूं और बस बेस पर विधि को कॉल कर सकता हूं लेकिन मुझे उम्मीद थी कि ऐसा करने का एक बेहतर तरीका है। मेरे पास अन्य वर्ग हैं जो विभिन्न डेटा प्रकारों के आधार पर आधार से प्राप्त होते हैं और मेरे पास अन्य कक्षाएं हैं जो IDoubleDo कुछ से प्राप्त होती हैं जो बेस का उपयोग नहीं करती हैं।

किसी भी मदद की सराहना की।

+2

क्या इस के साथ इतना बुरा है, और किस तरह से यह "बेहतर" हो सकता है? –

+2

मुझे लगता है कि "बेहतर" सी # संस्करण की तरह अभिनय करेगा जहां 'फू' बेस से विधि प्राप्त करता है और किसी भी कार्यान्वयन की आवश्यकता नहीं होती है। मुझे लगता है कि फू में बेस से प्रत्येक विधि के कार्यान्वयन के साथ वास्तव में कुछ भी बुरा नहीं है, यह सिर्फ गन्दा लगता है। – Clueless

+0

यह गन्दा है, लेकिन मुझे कभी भी बेहतर तरीका नहीं मिला है :( –

उत्तर

1

जैसा कि अन्य ने ध्यान दिया है, आधार वर्गों में दो कार्य असंबंधित हैं (समान नाम और तर्क प्रकार होने के बावजूद), क्योंकि उनके पास कोई सामान्य आधार वर्ग नहीं है। यदि आप उन्हें संबंधित होना चाहते हैं, तो आपको उन्हें एक सामान्य आधार वर्ग देना होगा।

इसके अलावा, यदि आप कई विरासत को सही तरीके से काम करना चाहते हैं, तो आपको अपने गैर-निजी आधार वर्गों को virtual के रूप में घोषित करने की आवश्यकता है। अन्यथा, यदि आपके पास कभी भी सामान्य आधार वर्ग होते हैं (जैसा कि आपको अक्सर कोड की इस शैली की आवश्यकता होती है), बुरी चीजें होती हैं।

तो यह देखते हुए कि, आप अपने उदाहरण काम इस प्रकार कर सकते हैं:

template <class T> 
class IDoSomething { 
public: 
    virtual void DoSomething(T value) = 0; 
}; 

template <class T> 
class Base : public virtual IDoSomething<T> 
{ 
public: 
    virtual void DoSomething(T value) 
    { 
     // Do something here 
    } 
}; 

class IDoubleDoSomething : public virtual IDoSomething<double> 
{ 
}; 

class Foo : public virtual Base<double>, public virtual IDoubleDoSomething 
{ 
}; 
+0

यह जो मैं प्राप्त करने की कोशिश कर रहा था उसके सबसे नज़दीक प्रतीत होता है और, क्योंकि मेरे पास 'बेस' है, यह मेरे परिदृश्य के लिए अच्छा काम करता है। अगर मैं 'बेस' के मालिक नहीं था तो मुझे लगता है कि यहां अन्य समाधान अधिक लागू होंगे। – Clueless

2

पर विचार करें निम्नलिखित C++ कोड

class Foo 
{ 
public: 
    void DoSomething1(){} 
}; 

template<typename t> 
void MethodExpectsDosomething1(t f) 
{ 
    f.DoSomething1(); 
} 

template<typename t> 
void MethodExpectsDosomething2(t f) 
{ 
    f.DoSomething2(); 
} 

int main() 
{ 
    Foo f; 
    MethodExpectsDosomething1<Foo>(f); 

    MethodExpectsDosomething2<Foo>(f); 

    return 0; 
} 

C++ में आप इसे एक IDoSomething1 और IDoSomething2 को लागू करने के बिना Foo उपयोग कर सकते हैं। दूसरी विधि MethodExpectsDosomething2 संकलित करने में असफल हो जाएगी क्योंकि Foo में DoSomething2 विधि नहीं है।

सी # ऐसे निर्माण में संभव नहीं है और आपको IDoSomething1 और IDoSomething2 इंटरफेस रखने के लिए मजबूर करता है और type constraint के रूप में निर्दिष्ट करता है।

तो शायद आपको अपना कोड देखना होगा और देखें कि ऐसे इंटरफेस की आवश्यकता क्यों है?

+0

बतख-टाइपिंग के साथ समस्या यह है कि यह स्वयं-दस्तावेज नहीं है, जबकि बहुलकवाद शामिल समाधान स्वयं-दस्तावेज है। – akappa

+0

यदि बतख-टाइपिंग इतनी थी बुरा ... सी # 4.0 ने इसे 'डायनामिक' कीवर्ड के रूप में पेश नहीं किया होगा। सिर्फ इसलिए कि आपको कुल्हाड़ी दी जाती है, इसका मतलब यह नहीं है कि आपको अपने पैरों को काटना है –

+0

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

-1

प्रदान किया गया सब कुछ क्रम में है, यह काम करना चाहिए।

class Foo : public Base<double> 
{ 
}; 

आपके मूल कोड में Foo में 2 शून्य DoSomething (डबल मान) विधियां (1 सार तत्व) होगी। यह एक मूल भाग होगा और एक IDoubleDo कुछ हिस्सा होगा। फू :: बेस और फू :: IDoubleDo कुछ। आप इसे अस्थायी रूप से देने और कार्यान्वित करके IDoubleDoSomething.DoSomething() पर आज़मा सकते हैं।

लेकिन चूंकि फू पहले से ही बेस "" एक है "तुम क्या आप IDoubleDoSomething बिना की जरूरत है

+2

इंटरफ़ेस का उपयोग करने का कारण आधार या व्युत्पन्न कक्षा की परिभाषा के बिना इसे पॉइंटर पास करना है। इंटरफेस वर्ग को खत्म करना पीछे की तरफ जा रहा है। –

2

सी ++ में, शुद्ध आभासी कार्यों हमेशा एक व्युत्पन्न वर्ग में अधिरोहित किया जाना चाहिए;। वे अन्य आधार से ओवरराइड वारिस नहीं कर सकते हैं इस तरह की कक्षाएं। यदि आपको गतिशील बहुरूपता की आवश्यकता है, तो मुझे नहीं लगता कि Foo में फ़ंक्शन लिखने के लिए कोई समझदार विकल्प है जो Base फ़ंक्शन को कॉल करता है। ध्यान दें कि Base फ़ंक्शन को वर्चुअल होने की आवश्यकता नहीं है।

इस वर्ग के उपयोग के आधार पर (विशेष रूप से इंटरफ़ेस के प्रत्येक उदाहरण का वास्तविक प्रकार संकलित समय पर ज्ञात है) के आधार पर, आप अपने विशेष कार्यान्वयन वर्ग को अपने उपयोगकर्ता में इंजेक्ट करने के लिए स्थिर पॉलीमोर्फिज्म का उपयोग करने में सक्षम हो सकते हैं एक टेम्पलेट पैरामीटर के रूप में; उदाहरण के लिए:

// No explicit interface specification with static polymorphism 
class Foo : public Base<double> 
{ 
    // Inherits DoSomething(double) 
}; 

// Template can used with any class that impelements a 
// "DoSomething" function that can accept a double. 
template <class DoubleDoSomething> 
void DoSomethingWithDouble(DoubleDoSomething & interface, double value) 
{ 
    interface.DoSomething(value); 
} 

// This particular specialisation uses a "Foo" object. 
Foo foo; 
DoSomethingWithDouble(foo, 42); 
2

बात है, Base::DoSomething और IWhatever::DoSomething दो असंबंधित कार्यों (भले ही इस में किसी भी शुद्ध आभासी काम करता है, आप, वैसे भी एक Foo वस्तु पर DoSomething कॉल करने के लिए सक्षम नहीं होगा नहीं थे कर रहे हैं)। इस काम के लिए Base को IWhatever से प्राप्त करने की आवश्यकता है।

उसने कहा, खुद से पूछें कि आपको वास्तव में इसकी आवश्यकता है या नहीं। टेम्पलेट्स के साथ जेनेरिक प्रोग्रामिंग (और अवधारणाएं, जो इंटरफेस की तरह हैं - Boost.ConceptCheck देखें) आमतौर पर रनटाइम सबटाइप पॉलिमॉर्फिज्म की तुलना में सी ++ में बेहतर समाधान होता है।

2

आप बेस के लिए एक दूसरी टेम्पलेट पैरामीटर गुजर सकता है, इंटरफ़ेस यह है कि लागू करने के लिए:

template <typename T, class Interface> 
class Base : public Interface { ... }; 

class Foo : public Base<double, IDoubleDoSomething> { ... }; 

अतिरिक्त बोनस अंक आप IDoubleDoSomething templatise सकता है के लिए (इसलिए यह जैसे IDoSomething<double> है), या करने के लिए एक लक्षण वर्ग का उपयोग संबंधित इंटरफ़ेस में टाइप टी को मानचित्र करें।