बहुरूपता के लिए / आवश्यकताओं की समझ
बहुरूपता को समझने के लिए - जैसा कि इस शब्द का उपयोग कम्प्यूटिंग साइंस में किया जाता है - यह इसके लिए एक सरल परीक्षा से शुरू करने में मदद करता है। विचार करें:
Type1 x;
Type2 y;
f(x);
f(y);
यहाँ, f()
कुछ ऑपरेशन करना है और मान दिया जा रहा है x
और y
इनपुट के रूप में।
प्रदर्शनी बहुरूपता करने के लिए, f()
कम से कम दो के मूल्यों के साथ काम करने में सक्षम होना चाहिए अलग प्रकार (उदाहरण के लिए int
और double
), खोजने और अलग प्रकार की दृष्टि से उचित कोड को क्रियान्वित।
बहुरूपता के लिए सी ++ तंत्र
स्पष्ट प्रोग्रामर-निर्दिष्ट बहुरूपता
आप ऐसा लिख f()
सकते हैं कि यह निम्नलिखित में से किसी भी तरीके से कई प्रकारों पर काम कर सकता है:
preprocessing:
#define f(X) ((X) += 2)
// (note: in real code, use a longer uppercase name for a macro!)
ओवरलोडिंग:
void f(int& x) { x += 2; }
void f(double& x) { x += 2; }
टेम्पलेट:
template <typename T>
void f(T& x) { x += 2; }
आभासी प्रेषण:
struct Base { virtual Base& operator+=(int) = 0; };
struct X : Base
{
X(int n) : n_(n) { }
X& operator+=(int n) { n_ += n; return *this; }
int n_;
};
struct Y : Base
{
Y(double n) : n_(n) { }
Y& operator+=(int n) { n_ += n; return *this; }
double n_;
};
void f(Base& x) { x += 2; } // run-time polymorphic dispatch
अन्य संबंधित तंत्र
कंपाइलर-प्रदत्त बहुरूपता के लिए निर्मित प्रकार, मानक रूपांतरण और कास्टिंग / जबरदस्ती के बारे में बाद में पूर्णता के लिए चर्चा की जाती है:
- वे वैसे भी सहजता से समझ जाते हैं (" ओह, कि " प्रतिक्रिया "पर वारंट करते हुए)
- वे उपर्युक्त तंत्रों और, का उपयोग करने में आवश्यकता और सीमा में प्रभाव को प्रभावित करते हैं
- स्पष्टीकरण अधिक महत्वपूर्ण अवधारणाओं से एक काल्पनिक व्याकुलता है।
शब्दावली
आगे वर्गीकरण
उपरोक्त बहुरूपी तंत्र को देखते हुए, हम उन्हें विभिन्न तरीकों से वर्गीकृत कर सकते हैं:
1 - टेम्प्लेट बेहद लचीले होते हैं। SFINAE (यह भी देखें std::enable_if
) प्रभावी ढंग से पैरामीट्रिक बहुरूपता के लिए उम्मीदों के कई सेट की अनुमति देता है। उदाहरण के लिए, आप .size()
यह समझ सकते हैं कि जब आप जिस प्रकार के डेटा को संसाधित कर रहे हैं, उसका एक सदस्य है तो आप एक फ़ंक्शन का उपयोग करेंगे, अन्यथा किसी अन्य फ़ंक्शन की आवश्यकता नहीं है .size()
(लेकिन संभवतः किसी तरह से ग्रस्त है - जैसे कि धीमी का उपयोग करना strlen()
या मुद्रण के रूप में नहीं। लॉग में उपयोगी संदेश)। जब आप विशिष्ट मापदंडों के साथ त्वरित किया जाता है तो आप तदर्थ व्यवहार भी निर्दिष्ट कर सकते हैं, या तो कुछ पैरामीटर पैरामीट्रिक ( आंशिक टेम्पलेट विशेषज्ञता ) या नहीं छोड़ना ( पूर्ण विशेषज्ञता )।
"बहुरूपी"
अल्फ स्टीनबाक टिप्पणी करता है कि सी ++ में मानक बहुरूपता केवल आभासी प्रेषण का उपयोग करके रन-टाइम बहुरूपता को संदर्भित करता है। सामान्य COMP। विज्ञान। C ++ निर्माता बज़्ने स्ट्रॉस्ट्रुप की शब्दावली ( http://www.stroustrup.com/glossary.html ) के अनुसार अर्थ अधिक समावेशी है :
बहुरूपता - विभिन्न प्रकार की संस्थाओं को एक एकल इंटरफ़ेस प्रदान करना। वर्चुअल फ़ंक्शंस एक बेस क्लास द्वारा दिए गए इंटरफ़ेस के माध्यम से गतिशील (रन-टाइम) बहुरूपता प्रदान करते हैं। अतिभारित कार्य और टेम्पलेट स्थैतिक (संकलन-समय) बहुरूपता प्रदान करते हैं। टीसी ++ पीएल 12.2.6, 13.6.1, डी एंड ई 2.9।
यह उत्तर - प्रश्न की तरह - COMP से C ++ सुविधाओं से संबंधित है। विज्ञान। शब्दावली।
विचार-विमर्श
C ++ मानक के साथ Comp की तुलना में "बहुरूपता" की एक संकीर्ण परिभाषा का उपयोग करते हुए। विज्ञान। समुदाय, अपने दर्शकों के लिए आपसी समझ सुनिश्चित करने के लिए ...
- असंदिग्ध शब्दावली का उपयोग करते हुए ("क्या हम इस कोड को अन्य प्रकारों के लिए पुन: प्रयोज्य बना सकते हैं?" या "क्या हम वर्चुअल डिस्पैच का उपयोग कर सकते हैं?" के बजाय "क्या हम इस कोड को पॉलीमॉर्फिक बना सकते हैं?"), और / या
- अपनी शब्दावली को स्पष्ट रूप से परिभाषित करना।
फिर भी, एक महान C ++ प्रोग्रामर होने के लिए क्या महत्वपूर्ण है यह समझना कि बहुरूपता वास्तव में आपके लिए क्या कर रहा है ...
आपको एक बार "एल्गोरिथम" कोड लिखने की अनुमति देता है और फिर इसे कई प्रकार के डेटा पर लागू करता है
... और फिर इस बात से अवगत रहें कि विभिन्न पॉलिमर तंत्र आपकी वास्तविक जरूरतों से कैसे मेल खाते हैं।
रन-टाइम बहुरूपता सूट:
- फैक्ट्री विधियों द्वारा संसाधित इनपुट और विषम वस्तु संग्रह के रूप में बाहर थूक
Base*
एस, के माध्यम से संभाला
- कॉन्फ़िगरेशन फ़ाइलों, कमांड लाइन स्विच, यूआई सेटिंग्स आदि के आधार पर रनटाइम पर चुना गया कार्यान्वयन।
- रनटाइम पर विविध कार्यान्वयन, जैसे कि एक राज्य मशीन पैटर्न के लिए।
जब रन-टाइम बहुरूपता के लिए एक स्पष्ट ड्राइवर नहीं है, तो संकलन-समय विकल्प अक्सर बेहतर होते हैं। विचार करें:
- टेम्प्लेटेड कक्षाओं का संकलन-व्हाट्स-तथाकथित पहलू रनटाइम में विफल वसा इंटरफेस के लिए बेहतर है
- SFINAE
- CRTP
- अनुकूलन (कई इनलाइनिंग और डेड कोड एलिमिनेशन, लूप अनरोलिंग, स्टैटिक स्टैक-आधारित सरणियाँ बनाम ढेर)
__FILE__
, __LINE__
स्ट्रिंग शाब्दिक संयोजन और मैक्रोज़ की अन्य अनूठी क्षमताएं (जो बुराई बनी रहती हैं ;-))
- टेम्प्लेट और मैक्रोज़ टेस्ट सिमेंटिक उपयोग समर्थित है, लेकिन कृत्रिम रूप से उस समर्थन को प्रतिबंधित नहीं किया जाता है (जैसा कि वर्चुअल डिस्पैच बिल्कुल मिलान सदस्य फ़ंक्शन ओवरराइड की आवश्यकता होती है)
बहुरूपता का समर्थन करने वाले अन्य तंत्र
जैसा कि वादा किया गया था, पूर्णता के लिए कई परिधीय विषय शामिल हैं:
- संकलक-प्रदत्त अधिभार
- रूपांतरण
- डाले / बलात्कार
यह उत्तर इस बात की चर्चा के साथ समाप्त होता है कि कैसे पॉलिमॉर्फिक कोड को सशक्त और सरल बनाने के लिए उपरोक्त संयोजन - विशेष रूप से पैरामीट्रिक पॉलीमॉर्फिज़्म (टेम्प्लेट और मैक्रोज़)।
टाइपिंग-विशिष्ट संचालन के लिए मानचित्रण के लिए तंत्र
> जटिल संकलक-प्रदत्त ओवरलोड
वैचारिक रूप से, कंपाइलर बिलिन प्रकारों के लिए कई ऑपरेटरों को अधिभारित करता है। यह उपयोगकर्ता द्वारा निर्दिष्ट ओवरलोडिंग से वैचारिक रूप से भिन्न नहीं है, लेकिन इसे आसानी से अनदेखा किए जाने के रूप में सूचीबद्ध किया गया है। उदाहरण के लिए, आप एक ही संकेतन का उपयोग करके int
एस और double
एस जोड़ सकते हैं x += 2
और संकलक का उत्पादन करता है:
- प्रकार-विशिष्ट CPU निर्देश
- उसी प्रकार का परिणाम है।
फिर ओवरलोडिंग उपयोगकर्ता-परिभाषित प्रकारों तक मूल रूप से फैलती है:
std::string x;
int y = 0;
x += 'c';
y += 'c';
उच्च-स्तरीय (3GL +) कंप्यूटर भाषाओं में मूल प्रकारों के लिए संकलक-प्रदान किए गए ओवरलोड आम हैं, और बहुरूपता की स्पष्ट चर्चा आम तौर पर कुछ और होती है। (2GLs - असेंबली लैंग्वेज - अक्सर प्रोग्रामर को स्पष्ट रूप से विभिन्न प्रकारों के लिए अलग-अलग mnemonics का उपयोग करने की आवश्यकता होती है।)
> मानक रूपांतरण
C ++ मानक का चौथा खंड मानक रूपांतरणों का वर्णन करता है।
पहला बिंदु संक्षेप में (एक पुराने मसौदे से - उम्मीद है कि अभी भी काफी हद तक सही है):
-1- मानक रूपांतरण अंतर्निहित रूपांतरण हैं जो अंतर्निहित प्रकारों के लिए परिभाषित किए गए हैं। खण्ड-खण्ड इस तरह के रूपांतरणों के पूर्ण सेट को दर्शाता है। एक मानक रूपांतरण अनुक्रम निम्नलिखित क्रम में मानक रूपांतरणों का एक क्रम है:
निम्नलिखित सेट से शून्य या एक रूपांतरण: lvalue-to-rvalue रूपांतरण, सरणी-से-पॉइंटर रूपांतरण और फ़ंक्शन-टू-पॉइंटर रूपांतरण।
निम्नलिखित सेट से शून्य या एक रूपांतरण: इंटीग्रल प्रमोशन, फ्लोटिंग पॉइंट प्रमोशन, इंटीग्रल कन्वर्सेशन, फ्लोटिंग पॉइंट कन्वर्सेशन, फ्लोटिंग-इंटीग्रल कन्वर्सेशन, पॉइंटर कन्वर्सेशन, मेम्बर टू मेम्बर कन्वर्जन और बुलियन कन्वर्सेशन।
शून्य या एक योग्यता रूपांतरण।
[नोट: एक मानक रूपांतरण अनुक्रम खाली हो सकता है, अर्थात, इसमें कोई रूपांतरण नहीं हो सकता है। ] आवश्यक गंतव्य प्रकार में परिवर्तित करने के लिए यदि आवश्यक हो तो एक मानक रूपांतरण अनुक्रम एक अभिव्यक्ति पर लागू किया जाएगा।
ये रूपांतरण कोड की अनुमति देते हैं जैसे:
double a(double x) { return x + 2; }
a(3.14);
a(42);
पहले के परीक्षण को लागू करना:
बहुरूपी होने के लिए, [ a()
] कम से कम दो के मूल्यों के साथ काम करने में सक्षम होना चाहिए अलग प्रकार (उदाहरण के लिए int
और double
), खोजने और क्रियान्वित प्रकार उचित कोड ।
a()
खुद के लिए विशेष रूप से कोड चलाता है double
और इसलिए बहुरूपी नहीं है।
लेकिन, a()
कंपाइलर को दूसरी कॉल में "फ्लोटिंग पॉइंट प्रमोशन" (स्टैंडर्ड to4) के लिए टाइप-उपयुक्त कोड जनरेट करना जानता 42
है 42.0
। कॉलिंग फ़ंक्शन में वह अतिरिक्त कोड है । हम निष्कर्ष में इसके महत्व पर चर्चा करेंगे।
> ज़बरदस्ती, जातियां, निहित निर्माण
ये तंत्र उपयोगकर्ता-परिभाषित वर्गों को बिलिन प्रकार के मानक रूपांतरणों के समान व्यवहार को निर्दिष्ट करने की अनुमति देते हैं। चलो देखते हैं:
int a, b;
if (std::cin >> a >> b)
f(a, b);
यहाँ, वस्तु std::cin
का मूल्यांकन एक बूलियन संदर्भ में किया जाता है, रूपांतरण ऑपरेटर की सहायता से। यह वैचारिक रूप से उपरोक्त विषय में मानक रूपांतरणों से "अभिन्न प्रचार" एट अल के साथ समूहीकृत किया जा सकता है।
प्रभावी निर्माणकर्ता प्रभावी रूप से एक ही काम करते हैं, लेकिन कलाकारों द्वारा टाइप करने के लिए नियंत्रित होते हैं:
f(const std::string& x);
f("hello"); // invokes `std::string::string(const char*)`
संकलक-प्रदत्त अधिभार, रूपांतरण और जबरदस्ती के निहितार्थ
विचार करें:
void f()
{
typedef int Amount;
Amount x = 13;
x /= 2;
std::cout << x * 1.1;
}
यदि हम चाहते हैं कि राशि x
को विभाजन के दौरान एक वास्तविक संख्या के रूप में माना जाए (अर्थात 6 से 6 के बजाय 6.5 हो), तो हम केवल परिवर्तन करते हैं typedef double Amount
।
यह अच्छा है, लेकिन यह कोड को स्पष्ट रूप से "प्रकार सही" बनाने के लिए बहुत अधिक काम नहीं होगा :
void f() void f()
{ {
typedef int Amount; typedef double Amount;
Amount x = 13; Amount x = 13.0;
x /= 2; x /= 2.0;
std::cout << double(x) * 1.1; std::cout << x * 1.1;
} }
लेकिन, विचार करें कि हम पहले संस्करण को एक में बदल सकते हैं template
:
template <typename Amount>
void f()
{
Amount x = 13;
x /= 2;
std::cout << x * 1.1;
}
यह उन छोटी "सुविधा सुविधाओं" के कारण है कि यह या तो आसानी से त्वरित रूप से तैयार की जा सकती है int
या double
इरादा के अनुसार काम कर सकती है । इन सुविधाओं के बिना, हमें स्पष्ट जाति, प्रकार के लक्षण और / या नीति वर्ग, कुछ क्रिया, त्रुटि-प्रवण गंदगी की आवश्यकता होगी:
template <typename Amount, typename Policy>
void f()
{
Amount x = Policy::thirteen;
x /= static_cast<Amount>(2);
std::cout << traits<Amount>::to_double(x) * 1.1;
}
इसलिए, कंपाइलर प्रदान करने वाले ऑपरेटर बिलिन प्रकारों के लिए ओवरलोडिंग, मानक रूपांतरण, कास्टिंग / जबरदस्ती / निहित निर्माणकर्ता - ये सभी बहुरूपता के लिए सूक्ष्म समर्थन में योगदान करते हैं। इस उत्तर के शीर्ष पर परिभाषा से, वे मैपिंग के द्वारा "टाइप-उपयुक्त कोड को खोजने और निष्पादित करने" को संबोधित करते हैं:
वे स्वयं द्वारा बहुरूपिक संदर्भों की स्थापना नहीं करते हैं, लेकिन ऐसे संदर्भों के अंदर कोड को सशक्त बनाने / सरल बनाने में सहायता करते हैं।
आप ठगा हुआ महसूस कर सकते हैं ... ऐसा नहीं लगता है। महत्व यह है कि पैरामीट्रिक पॉलीमॉर्फिक संदर्भों में (अर्थात टेम्प्लेट या मैक्रोज़ के अंदर), हम मनमाने ढंग से बड़ी रेंज का समर्थन करने की कोशिश कर रहे हैं, लेकिन अक्सर उन पर अन्य कार्यों, शाब्दिक और संचालन के संदर्भ में संचालन व्यक्त करना चाहते हैं जो इसके लिए डिज़ाइन किए गए थे छोटे प्रकार के सेट। यह ऑपरेशन / मूल्य तार्किक रूप से समान होने पर प्रति-प्रकार के आधार पर निकट-समान फ़ंक्शन या डेटा बनाने की आवश्यकता को कम करता है। ये सुविधाएँ "सर्वोत्तम प्रयास" के एक दृष्टिकोण को जोड़ने के लिए सहयोग करती हैं, जो कि सीमित उपलब्ध कार्यों और डेटा का उपयोग करके सहजता से अपेक्षित है और वास्तविक अस्पष्टता होने पर केवल एक त्रुटि के साथ रुकती है।
यह बहुरूपता का समर्थन करने वाले बहुरूपिक कोड की आवश्यकता को सीमित करने में मदद करता है, बहुरूपता के उपयोग के आस-पास एक तंग जाल खींचता है ताकि स्थानीय उपयोग व्यापक उपयोग को मजबूर न करे, और कार्यान्वयन पर होने वाले खर्चों को लागू किए बिना आवश्यकता के बिना बहुरूपता के लाभ उपलब्ध कराए। संकलित समय, उपयोग किए गए प्रकारों का समर्थन करने के लिए ऑब्जेक्ट कोड में एक ही तार्किक फ़ंक्शन की कई प्रतियां हैं, और इनलाइनिंग या कम से कम संकलन-समय हल कॉल के विपरीत आभासी प्रेषण करने में। जैसा कि C ++ में विशिष्ट है, प्रोग्रामर को उन सीमाओं को नियंत्रित करने के लिए बहुत अधिक स्वतंत्रता दी जाती है जिनके भीतर बहुरूपता का उपयोग किया जाता है।