इंटरफेस (पूरी तरह से वर्चुअल वर्चुअल फ़ंक्शंस के साथ पॉलिमॉर्फिक क्लास) में एक vtable है? चूंकि इंटरफेस स्वयं पॉलिमॉर्फिक फ़ंक्शन को लागू नहीं करते हैं और सीधे निर्मित नहीं किए जाते हैं, तो लिंकर को vtable रखने की आवश्यकता नहीं होगी। ऐसा क्या? मैं विशेष रूप से एमएसवीसी संकलक के बारे में चिंतित हूं।इंटरफ़ेस vtable
उत्तर
हाँ, वे करते हैं (सामान्य भाषा में, कार्यान्वयन में, एक अमूर्त वर्ग एक vtable, उदा .:
struct Base {
Base();
virtual void f() {}
virtual void g() = 0;
};
void h(Base& b) {
b.f(); // Call f on a Base that is not (yet) a Derived
// vtable for Base required
}
Base::Base() {
h(*this);
}
struct Derived : Base {
void g() {}
};
int main() {
Derived d;
}
आवश्यकता हो सकती है)। और इसके लिए कई अच्छे कारण हैं।
पहला अच्छा कारण यह है कि शुद्ध वर्चुअल विधियों में भी कार्यान्वयन है। या तो निहित या स्पष्ट। एक शुद्ध वर्चुअल फ़ंक्शन को कॉल करने वाली चाल को खींचना अपेक्षाकृत आसान है, इसलिए आप मूल रूप से अपने किसी एक के लिए परिभाषा प्रदान कर सकते हैं, इसे कॉल कर सकते हैं और देख सकते हैं कि क्या होता है। इसी कारण से, पहली जगह में वर्चुअल टेबल होना चाहिए।
वर्चुअल टेबल को बेस क्लास में डालने का एक और कारण है, भले ही इसकी सभी विधियां शुद्ध वर्चुअल हों और फिर कोई अन्य डेटा सदस्य न हों। जब बहुरूपता का उपयोग किया जाता है, तो बेस क्लास के लिए पॉइंटर प्रोग्राम के चारों ओर पारित किया जाता है। वर्चुअल विधि को कॉल करने के लिए, कंपाइलर/रनटाइम को बेस पॉइंटर से आभासी तालिका के सापेक्ष ऑफसेट को समझना चाहिए। यदि सी ++ में कोई एकाधिक विरासत नहीं थी, तो कोई भी सार आधार वर्ग (उदाहरण के लिए) से शून्य ऑफ़सेट मान सकता है, इस मामले में वहां संभवतः एक vtable नहीं होना संभव था (लेकिन हमें अभी भी कारण # 1 के कारण इसकी आवश्यकता है)। लेकिन चूंकि एक से अधिक विरासत शामिल है, इसलिए एक चाल अला "vtable 0 ऑफसेट पर है" काम नहीं करेगा क्योंकि आधार वर्गों की संख्या (और प्रकार) के आधार पर दो या तीन vtables हो सकते हैं।
अन्य कारण भी हो सकते हैं जो मेरे पास भी नहीं हैं।
उम्मीद है कि यह मदद करता है।
अच्छा तर्क! इसके बारे में सोचा नहीं है। –
जिस चाल का आप उल्लेख करते हैं, वह वह है जिसे शुद्ध वर्चुअल फ़ंक्शन को परिभाषित करने की आवश्यकता नहीं है (_odr_ नियमों के तहत) या अन्यथा अपरिभाषित व्यवहार का कारण बनता है क्योंकि मुझे ऐसी किसी भी चाल से अवगत नहीं था? –
मैं आपके पहले कारण से आश्वस्त नहीं हूं। मुझे पूरा यकीन है कि शुद्ध वर्चुअल फ़ंक्शन को कॉल करने का एकमात्र तरीका है (ए) इसे गैर-वर्चुअल रूप से कॉल करें, जो vtable का उपयोग नहीं करता है, या (बी) इसे आंशिक रूप से कन्स्ट्रक्टर/विनाशक से बुलाकर अपरिभाषित व्यवहार का आह्वान करता है निर्मित वस्तु, जिसे इसे बिल्कुल कॉल करने की आवश्यकता नहीं है। या क्या आप एक और चाल जानते हैं जो मैं नहीं करता? –
पूरी तरह से सी ++ बिंदु से यह एक अकादमिक प्रश्न है। आभासी कार्यों को vtables के साथ लागू करने की आवश्यकता नहीं है, अगर वे वहां पहुंचने के लिए कोई पोर्टेबल तरीका नहीं है।
यदि आप एमएसवीसी कंपाइलर के बारे में विशेष रूप से चिंतित हैं तो आप __declspec(novtable)
के साथ अपने इंटरफेस को सजाना चाहते हैं।
मैं देखना चाहता हूं कि वर्चुअल टेबल या किसी अन्य दृष्टिकोण का उपयोग न करने के लिए उन्हें कैसे कार्यान्वित किया जा सकता है, जहां कम से कम आकार (शून्य *) को "प्रारंभ बिंदु" के रूप में सेवा देने वाले वर्ग में जोड़ा जाना चाहिए ... –
@VladLazarenko: मुझे लगता है कि यह है लगभग सार्वभौमिक रूप से स्वीकार किया जाता है कि एक vptr/vtable आधारित समाधान इष्टतम है लेकिन कुछ रूपों की गतिशील प्रकार की जानकारी के पते के मानचित्र को संग्रहीत करने के लिए अव्यवहारिक कार्यान्वयन कम से कम सैद्धांतिक रूप से संभव है। –
आपको पॉइंट मिला।मुझे लगता है कि मेरा मतलब यह है कि इससे कोई फर्क नहीं पड़ता कि आप इसे कैसे कॉल करते हैं, आपको इसे कम से कम कुछ शुरुआती बिंदु की आवश्यकता होगी, यह सुनिश्चित करने के लिए कि एक पॉइंटर vtable, पते के साथ हैश के लिए पॉइंटर या हैश के साथ कुछ ग्लोबल हैश संकेत दिए गए। –
vtable आवश्यक नहीं है, लेकिन शायद ही कभी अनुकूलित किया गया है। एमएसवीसी __declspec(novtable)
एक्सटेंशन प्रदान करता है, जो संकलक को स्पष्ट रूप से बताता है कि vtable को हटाया जा सकता है। इसकी अनुपस्थिति में, कंपाइलर को खुद को जांचना होगा कि vtable का उपयोग नहीं किया जाता है। यह असाधारण रूप से कठिन नहीं है, लेकिन अभी भी तुच्छ से दूर है। और चूंकि यह नियमित कोड में वास्तविक गति लाभ प्रदान नहीं करता है, इसलिए मुझे पता है कि किसी भी संकलक में चेक लागू नहीं किया गया है।
ए * बहुत * महत्वपूर्ण नोट एमएसवीसी में 'declspec (novtable)' सुविधा है: यह vtable को छोड़ने के लिए इंटरफेस, विशेष रूप से COM वाले को अनुमति देता है। जब विरासत की बात आती है तो इसमें कुछ रोचक और महत्वपूर्ण प्रभाव पड़ते हैं (एकल विरासत को बल देते हैं, लेकिन अंतिम वस्तु को केवल एक ही तालिका होती है जो अन्यथा की तुलना में अधिक बहुलक प्रदान करती है)। – ssube