C ++ में एक ही वर्ग के लिए विभिन्न प्रकारों को कैसे परिभाषित किया जाए


84

मैं कई प्रकारों को लागू करना चाहूंगा जो समान कार्यान्वयन को साझा करते हैं लेकिन फिर भी C ++ में विभिन्न प्रकार के हैं।

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

class Apple {
     int p;
public:
     Apple (int p) : p(p) {}
     int price () const {return p;}
}

class Banana {
     int p;
public:
     Banana (int p) : p(p) {}
     int price () const {return p;}
}

class Orange ...

कोड को डुप्लिकेट नहीं करने के लिए, ऐसा लगता है कि मैं एक बेस क्लास फल का उपयोग कर सकता हूं और इससे विरासत में मिला:

class Fruit {
     int p;
public:
     Fruit (int p) : p(p) {}
     int price () const {return p;}
}

class Apple: public Fruit {};
class Banana: public Fruit {};
class Orange: public Fruit {};

लेकिन फिर, कंस्ट्रक्टरों को विरासत में नहीं मिला है और मुझे उन्हें फिर से लिखना होगा।

क्या कोई तंत्र (टाइप्डफ्स, टेम्प्लेट, इनहेरिटेंस ...) है जो मुझे आसानी से विभिन्न प्रकारों के साथ एक ही वर्ग रखने की अनुमति देगा?


क्या आप अधिक विस्तार से बता सकते हैं कि आपको इसकी आवश्यकता क्यों होगी? मैं किसी अच्छे विचार के साथ नहीं आ सकता। यदि कक्षाएं कार्यान्वयन को साझा करती हैं, तो क्या इसका मतलब यह नहीं है कि वे कार्यक्षमता भी साझा करते हैं?
jnovacho

4
हां, लेकिन चूंकि उनके पास विभिन्न प्रकार होंगे, इसलिए कुछ प्रोग्रामिंग त्रुटियों को संकलन समय (उदाहरण के लिए, सेब और अजवायन को मिलाते हुए) में पता लगाया जा सकता है।
अउमी

जवाबों:


119

एक सामान्य तकनीक में एक क्लास टेम्प्लेट होता है, जहाँ टेम्प्लेट तर्क केवल एक अद्वितीय टोकन ("टैग") के रूप में कार्य करता है, ताकि यह एक अद्वितीय टेम्प्लेट बन सके:

template <typename Tag>
class Fruit {
    int p;
public:
    Fruit(int p) : p(p) { }
    int price() const { return p; }
};

using Apple = Fruit<struct AppleTag>;
using Banana = Fruit<struct BananaTag>;

ध्यान दें कि टैग कक्षाओं को परिभाषित करने की आवश्यकता नहीं है, यह एक अद्वितीय प्रकार का नाम घोषित करने के लिए पर्याप्त है । यह काम करता है क्योंकि टैग isn वास्तव में टेम्पलेट में कहीं भी उपयोग किया जाता है । और आप टेम्पलेट तर्क सूची (हैट टिप से @ Xeo) के अंदर टाइप नाम घोषित कर सकते हैं ।

usingवाक्य रचना सी ++ 11 है। यदि आप C ++ 03 के साथ फंस गए हैं, तो इसके बजाय इसे लिखें:

typedef Fruit<struct AppleTag> Apple;

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

दुर्भाग्य से, इसके लिए आपको सभी गैर-अंतर्निहित सदस्यों (निर्माणकर्ता, असाइनमेंट ...) को फिर से लागू करना होगा, जो एक छोटे से ओवरहेड को जोड़ता है - इसलिए यह केवल बड़ी कक्षाओं के लिए समझ में आता है। यहाँ इसे उपरोक्त उदाहरण पर लागू किया गया है:

// Actual `Fruit` class remains unchanged, except for template declaration
template <typename Tag, typename = Tag>
class Fruit { /* unchanged */ };

template <typename T>
class Fruit<T, T> : public Fruit<T, void> {
public:
    // Should work but doesn’t on my compiler:
    //using Fruit<T, void>::Fruit;
    Fruit(int p) : Fruit<T, void>(p) { }
};

using Apple = Fruit<struct AppleTag>;
using Banana = Fruit<struct BananaTag>;

+1, यदि आप व्यक्तिगत फलों के लिए कोई अतिरिक्त गुण निर्धारित नहीं करना चाहते हैं, तो मैं इसके साथ जाऊंगा ...
निम

20
आप वास्तव में उन्हें केवल टेम्पलेट तर्क सूची के अंदर घोषित कर सकते हैं, जो मुझे बहुत सुविधाजनक लगता है Fruit<struct SomeTag>:।
Xeo

1
@KonradRudolph यह शर्म की बात है कि मैं खुद को संपादित नहीं कर सकता ..... मैंने उस टिप्पणी को देखा ।
अनन्तमत्त

1
@eternalmatt LOL - मैंने कभी नहीं सोचा होगा कि कोई भी इसे देखेगा। लेकिन ठीक है, आप किसी की तलाश में भी मज़ेदार नहीं हो सकते। ;-)
कोनराड रुडोल्फ

2
इसका एक पहलू विभिन्न प्रकारों के लिए टेम्पलेट तात्कालिकता के कई उत्सर्जन है। क्या इन डुप्लिकेट को व्यापक रूप से उपयोग किए गए लिंकर्स द्वारा समाप्त कर दिया गया है?
बॉयसी

19

उपयोग टेम्पलेट्स, और एक का उपयोग विशेषता उदाहरण के लिए प्रति फल,:

struct AppleTraits
{
  // define apple specific traits (say, static methods, types etc)
  static int colour = 0; 
};

struct OrangeTraits
{
  // define orange specific traits (say, static methods, types etc)
  static int colour = 1; 
};

// etc

फिर एक एकल Fruitवर्ग है जो इस विशेषता पर टाइप किया गया है।

template <typename FruitTrait>
struct Fruit
{
  // All fruit methods...
  // Here return the colour from the traits class..
  int colour() const
  { return FruitTrait::colour; }
};

// Now use a few typedefs
typedef Fruit<AppleTraits> Apple;
typedef Fruit<OrangeTraits> Orange;

थोड़ा ओवरकिल हो सकता है! ;)



हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.