स्पष्ट बनाम स्पष्ट इंटरफेस


9

मुझे लगता है कि मैं संकलन-समय के बहुरूपता और रन-टाइम बहुरूपता की वास्तविक सीमाओं को समझता हूं। लेकिन स्पष्ट इंटरफेस (रन-टाइम पॉलिमोर्फिज्म। यानी वर्चुअल फ़ंक्शन और पॉइंटर्स / संदर्भ) और अंतर्निहित इंटरफेस (संकलन-समय पॉलीमोर्फिज्म। यानी टेम्प्लेट) के बीच वैचारिक अंतर क्या हैं

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

इस पर कोई विचार?

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

कुछ संबंधित पोस्ट:


इस प्रश्न को अधिक ठोस बनाने के लिए यहां एक उदाहरण दिया गया है:

निहित इंटरफ़ेस:

class Class1
{
public:
  void interfaceFunc();
  void otherFunc1();
};

class Class2
{
public:
  void interfaceFunc();
  void otherFunc2();
};

template <typename T>
class UseClass
{
public:
  void run(T & obj)
  {
    obj.interfaceFunc();
  }
};

स्पष्ट इंटरफ़ेस:

class InterfaceClass
{
public:
  virtual void interfaceFunc() = 0;
};

class Class1 : public InterfaceClass
{
public:
  virtual void interfaceFunc();
  void otherFunc1();
};

class Class2 : public InterfaceClass
{
public:
  virtual void interfaceFunc();
  void otherFunc2();
};

class UseClass
{
public:
  void run(InterfaceClass & obj)
  {
    obj.interfaceFunc();
  }
};

एक और भी अधिक गहराई में, ठोस उदाहरण:

कुछ C ++ समस्याओं को या तो हल किया जा सकता है:

  1. एक अस्थायी वर्ग जिसका टेम्पलेट प्रकार एक अंतर्निहित इंटरफ़ेस प्रदान करता है
  2. एक गैर-टेम्प्लेटेड क्लास जो एक बेस-क्लास पॉइंटर लेता है जो एक स्पष्ट इंटरफ़ेस प्रदान करता है

कोड जो नहीं बदलता है:

class CoolClass
{
public:
  virtual void doSomethingCool() = 0;
  virtual void worthless() = 0;
};

class CoolA : public CoolClass
{
public:
  virtual void doSomethingCool()
  { /* Do cool stuff that an A would do */ }

  virtual void worthless()
  { /* Worthless, but must be implemented */ }
};

class CoolB : public CoolClass
{
public:
  virtual void doSomethingCool()
  { /* Do cool stuff that a B would do */ }

  virtual void worthless()
  { /* Worthless, but must be implemented */ }
};

केस 1 । एक गैर-अस्थायी वर्ग जो एक बेस-क्लास पॉइंटर लेता है जो एक स्पष्ट इंटरफ़ेस प्रदान करता है:

class CoolClassUser
{
public:  
  void useCoolClass(CoolClass * coolClass)
  { coolClass.doSomethingCool(); }
};

int main()
{
  CoolA * c1 = new CoolClass;
  CoolB * c2 = new CoolClass;

  CoolClassUser user;
  user.useCoolClass(c1);
  user.useCoolClass(c2);

  return 0;
}

केस 2 । एक टेम्प्लेटेड क्लास जिसका टेम्प्लेट टाइप एक निहित इंटरफ़ेस प्रदान करता है:

template <typename T>
class CoolClassUser
{
public:  
  void useCoolClass(T * coolClass)
  { coolClass->doSomethingCool(); }
};

int main()
{
  CoolA * c1 = new CoolClass;
  CoolB * c2 = new CoolClass;

  CoolClassUser<CoolClass> user;
  user.useCoolClass(c1);
  user.useCoolClass(c2);

  return 0;
}

केस 3 । एक टेम्प्लेटेड क्लास जिसका टेम्प्लेट टाइप एक निहित इंटरफ़ेस प्रदान करता है (इस बार, इससे व्युत्पन्न नहीं CoolClass:

class RandomClass
{
public:
  void doSomethingCool()
  { /* Do cool stuff that a RandomClass would do */ }

  // I don't have to implement worthless()! Na na na na na!
}


template <typename T>
class CoolClassUser
{
public:  
  void useCoolClass(T * coolClass)
  { coolClass->doSomethingCool(); }
};

int main()
{
  RandomClass * c1 = new RandomClass;
  RandomClass * c2 = new RandomClass;

  CoolClassUser<RandomClass> user;
  user.useCoolClass(c1);
  user.useCoolClass(c2);

  return 0;
}

केस 1 के लिए आवश्यक है कि वस्तु useCoolClass()को CoolClass(और कार्यान्वित करने वाला worthless()) बच्चा हो । दूसरी ओर, मामले 2 और 3, किसी भी वर्ग को ले जाएगा जिसके पास एक doSomethingCool()फ़ंक्शन है।

यदि कोड के उपयोगकर्ता हमेशा ठीक उप-वर्ग होते थे CoolClass, तो केस 1 सहज ज्ञान युक्त बनाता है, क्योंकि CoolClassUserहमेशा एक के कार्यान्वयन की उम्मीद होगी CoolClass। लेकिन मान लें कि यह कोड एक API फ्रेमवर्क का हिस्सा होगा, इसलिए मैं यह अनुमान नहीं लगा सकता कि क्या उपयोगकर्ता CoolClassअपने स्वयं के वर्ग को उप-वर्ग करना या रोल करना चाहेंगे जिनके पास doSomethingCool()फ़ंक्शन है।


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

2
कुछ समस्याएं हैं जिनका समाधान या तो एक वर्ग या फ़ंक्शन होता है जो एक सूचक को एक अमूर्त वर्ग (जो एक स्पष्ट इंटरफ़ेस प्रदान करता है), या एक अस्थायी वर्ग या फ़ंक्शन होने से एक ऑब्जेक्ट का उपयोग करता है जो एक अंतर्निहित इंटरफ़ेस प्रदान करता है। दोनों समाधान काम करते हैं। आप पहले समाधान का उपयोग कब करना चाहेंगे? द्वितीय?
क्रिस मॉरिस

मुझे लगता है कि जब आप अवधारणाओं को थोड़ा और खोलते हैं तो इनमें से अधिकांश विचार अलग हो जाते हैं। उदाहरण के लिए, आप गैर-विरासत स्थैतिक बहुरूपता कहाँ फिट करेंगे?
जेवियर 19

जवाबों:


8

आपने पहले से ही महत्वपूर्ण बिंदु को परिभाषित किया है- एक रन-टाइम है और दूसरा संकलन-टाइम है । आपको जिस वास्तविक जानकारी की आवश्यकता है, वह इस विकल्प का प्रभाव है।

Compiletime:

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

रनटाइम:

  • प्रो: अंतिम प्रकार रन-टाइम तक तय नहीं किया जाना है। इसका मतलब है कि रन-टाइम इनहेरिटेंस कुछ डेटा संरचनाओं को बहुत आसान व्यक्त कर सकता है, अगर टेम्प्लेट इसे बिल्कुल भी कर सकते हैं। इसके अलावा, आप सी-सीमाओं के पार रन-टाइम बहुरूपी प्रकारों का निर्यात कर सकते हैं, उदाहरण के लिए, COM।
  • प्रो: रन-टाइम इनहेरिटेंस को निर्दिष्ट करना और लागू करना बहुत आसान है, और आपको वास्तव में कोई कंपाइलर-विशिष्ट व्यवहार नहीं मिलेगा।
  • Con: रन-टाइम इनहेरिटेंस संकलित-टाइम इनहेरिटेन की तुलना में धीमी हो सकती है।
  • Con: रन-टाइम वंशानुक्रम प्रकार की जानकारी खो देता है।
  • Con: रन-टाइम इनहेरिटेंस कम लचीला तरीका है।
  • Con: एकाधिक वंशानुक्रम एक कुतिया है।

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

संपादित करें: यह की कीमत यह देखते हुए कि C ++ विशेष रूप से वहाँ विरासत के लिए प्रयोग हैं अन्य रन-टाइम बहुरूपता से। उदाहरण के लिए, आप टाइप किए गए अक्षरों को इनहेरिट कर सकते हैं, या इसे टाइपिंग के लिए उपयोग कर सकते हैं, या CRTP का उपयोग कर सकते हैं। अंततः, हालांकि, ये तकनीकें (और अन्य) वास्तव में "संकलन-समय" के अंतर्गत आती हैं, भले ही उनका उपयोग करके लागू किया गया हो class X : public Y


संकलन के लिए आपके पहले समर्थक के बारे में, यह मेरे मुख्य प्रश्नों में से एक से संबंधित है। क्या आप कभी यह स्पष्ट करना चाहेंगे कि आप केवल एक स्पष्ट इंटरफ़ेस के साथ काम करना चाहते हैं। अर्थात। 'मुझे परवाह नहीं है अगर आपके पास मेरे लिए आवश्यक सभी कार्य हैं, यदि आपको कक्षा Z से विरासत में नहीं मिला है तो मुझे आपके साथ कुछ भी नहीं करना है।' इसके अलावा, रन-टाइम इनहेरिटेंस पॉइंटर्स / रेफरेंस का उपयोग करते समय टाइप की जानकारी नहीं खोता है, सही है?
क्रिस मॉरिस

@ क्रिसमोरिस: नहीं। अगर यह काम करता है तो यह काम करता है, जो आप सभी को ध्यान रखना चाहिए। क्यों किसी ने ठीक उसी कोड को कहीं और लिखा है?
jmoreno

1
@ क्रिसमोरिस: नहीं, मैं नहीं करूंगा। अगर मुझे केवल एक्स की आवश्यकता है, तो यह एनकैप्सुलेशन के मूल मूलभूत सिद्धांतों में से एक है जिसे मुझे केवल एक्स के बारे में कभी भी पूछना और देखभाल करना चाहिए। इसके अलावा, यह टाइप जानकारी खो देता है। उदाहरण के लिए, आप इस प्रकार के ऑब्जेक्ट को आवंटित नहीं कर सकते। आप इसके सही प्रकार के साथ एक टेम्पलेट को तत्काल नहीं कर सकते। आप उन पर templated सदस्य फ़ंक्शंस नहीं कह सकते।
डेडएमजी

ऐसी स्थिति के बारे में जहां आपके पास एक वर्ग क्यू है जो कुछ वर्ग का उपयोग करता है। क्यू एक टेम्प्लेट पैरामीटर लेता है, इसलिए जो भी वर्ग प्रदान करता है वह निहित इंटरफ़ेस करेगा, या इसलिए हम सोचते हैं। यह पता चला है कि वर्ग Q भी अपने आंतरिक वर्ग (इसे H कहता है) को Q के इंटरफ़ेस का उपयोग करने की उम्मीद है। उदाहरण के लिए, जब एच ऑब्जेक्ट को नष्ट किया जाता है, तो उसे क्यू के कुछ फ़ंक्शन को कॉल करना चाहिए। यह एक अंतर्निहित इंटरफ़ेस में निर्दिष्ट नहीं किया जा सकता है। इस प्रकार, टेम्पलेट विफल हो जाते हैं। अधिक स्पष्ट रूप से कहें तो, वर्गों का एक कसकर युग्मित सेट जिसे एक-दूसरे से अधिक अंतर्निहित इंटरफेस की आवश्यकता होती है, टेम्प्लेट के उपयोग को खराब करने लगता है।
क्रिस मॉरिस

Con compiletime: डिबग करने के लिए बदसूरत, परिभाषाओं को हेडर में डालने की आवश्यकता
JFFIGK
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.