मुझे लगता है कि मैं संकलन-समय के बहुरूपता और रन-टाइम बहुरूपता की वास्तविक सीमाओं को समझता हूं। लेकिन स्पष्ट इंटरफेस (रन-टाइम पॉलिमोर्फिज्म। यानी वर्चुअल फ़ंक्शन और पॉइंटर्स / संदर्भ) और अंतर्निहित इंटरफेस (संकलन-समय पॉलीमोर्फिज्म। यानी टेम्प्लेट) के बीच वैचारिक अंतर क्या हैं ।
मेरा विचार यह है कि दो वस्तुएं जो एक ही स्पष्ट इंटरफ़ेस प्रदान करती हैं, एक ही प्रकार की वस्तु (या एक सामान्य पूर्वज) होनी चाहिए, जबकि दो वस्तुएं जो एक ही अंतर्निहित इंटरफ़ेस की पेशकश करती हैं, एक ही प्रकार की वस्तु की आवश्यकता नहीं है, और, निहित को छोड़कर इंटरफ़ेस जो वे दोनों प्रदान करते हैं, इसमें काफी भिन्न कार्यक्षमता हो सकती है।
इस पर कोई विचार?
और अगर दो ऑब्जेक्ट एक ही अंतर्निहित इंटरफ़ेस प्रदान करते हैं, तो क्या कारण हैं (डायनेमिक डिस्पैच डब्ल्यू / एक वर्चुअल फ़ंक्शन लुकअप टेबल, आदि की आवश्यकता के तकनीकी लाभ के अलावा) इन ऑब्जेक्ट्स को आधार ऑब्जेक्ट से विरासत में प्राप्त नहीं होने के लिए हैं जो उस इंटरफ़ेस को घोषित करता है, इस प्रकार। यह एक स्पष्ट इंटरफ़ेस बनाने ? इसे कहने का एक और तरीका: क्या आप मुझे एक ऐसा मामला दे सकते हैं जहां दो वस्तुएं जो एक ही अंतर्निहित इंटरफ़ेस पेश करती हैं (और इसलिए इसे नमूना टेम्पलेट वर्ग के प्रकारों के रूप में इस्तेमाल किया जा सकता है) को उस आधार वर्ग से विरासत में नहीं मिलना चाहिए जो उस इंटरफ़ेस को स्पष्ट करता है?
कुछ संबंधित पोस्ट:
- https://stackoverflow.com/a/7264550/635125
- https://stackoverflow.com/a/7264689/635125
- https://stackoverflow.com/a/8009872/635125
इस प्रश्न को अधिक ठोस बनाने के लिए यहां एक उदाहरण दिया गया है:
निहित इंटरफ़ेस:
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 ++ समस्याओं को या तो हल किया जा सकता है:
- एक अस्थायी वर्ग जिसका टेम्पलेट प्रकार एक अंतर्निहित इंटरफ़ेस प्रदान करता है
- एक गैर-टेम्प्लेटेड क्लास जो एक बेस-क्लास पॉइंटर लेता है जो एक स्पष्ट इंटरफ़ेस प्रदान करता है
कोड जो नहीं बदलता है:
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()
फ़ंक्शन है।