आभासी तरीकों को आमतौर पर तथाकथित वर्चुअल विधि तालिकाओं (संक्षिप्त के लिए व्यवहार्य) के माध्यम से लागू किया जाता है, जिसमें फ़ंक्शन पॉइंटर्स संग्रहीत होते हैं। यह वास्तविक कॉल के लिए अप्रत्यक्ष जोड़ता है (व्यवहार का पता लगाने के लिए फ़ंक्शन का पता प्राप्त करना होगा, फिर इसे कॉल करें - जैसा कि अभी इसे आगे कॉल करने का विरोध किया गया है)। बेशक, इसमें कुछ समय और कुछ और कोड लगते हैं।
हालांकि, यह जरूरी नहीं है कि सुस्ती का प्राथमिक कारण है। असली समस्या यह है कि संकलक (आम तौर पर / आमतौर पर) यह नहीं जान सकता है कि किस फ़ंक्शन को कहा जाएगा। इसलिए यह इसे इनलाइन नहीं कर सकता है और न ही इस तरह के अन्य अनुकूलन कर सकता है। यह अकेले एक दर्जन व्यर्थ निर्देश (रजिस्टरों को तैयार करना, कॉल करना, फिर राज्य को बाद में बहाल करना) जोड़ सकता है, और अन्य को बाधित कर सकता है, प्रतीत होता है कि असंबंधित अनुकूलन। इसके अलावा, यदि आप कई अलग-अलग कार्यान्वयनों को कॉल करके पागलों की तरह शाखा करते हैं, तो आप उसी हिट्स को भुगतते हैं, जिसे आप अन्य माध्यमों से पागलों की तरह झेल रहे हैं: कैश और शाखा पूर्वसूचक आपकी मदद नहीं करेंगे, शाखाएं पूरी तरह से अनुमान लगाने में अधिक समय लेगी डाली।
बड़ा लेकिन : ये प्रदर्शन हिट आमतौर पर बात करने के लिए बहुत छोटे होते हैं। यदि आप एक उच्च-प्रदर्शन कोड बनाना चाहते हैं और एक वर्चुअल फ़ंक्शन जोड़ने पर विचार करना चाहते हैं जो कि खतरनाक आवृत्ति पर कहा जाएगा। हालांकि, यह भी ध्यान रखें कि शाखाओं के अन्य साधनों के साथ आभासी समारोह कॉल की जगह ( if .. else
, switch
, समारोह संकेत, आदि) मौलिक समस्या का समाधान नहीं होगा - यह बहुत अच्छी तरह से धीमी हो सकती है। समस्या (यदि यह सभी में मौजूद है) आभासी कार्य नहीं है लेकिन (अनावश्यक) अप्रत्यक्ष है।
संपादित करें: कॉल निर्देशों में अंतर अन्य उत्तरों में वर्णित है। मूल रूप से, एक स्थिर ("सामान्य") कॉल के लिए कोड है:
- स्टैक पर कुछ रजिस्टरों को कॉपी करें, उन फ़ंक्शन को उन रजिस्टरों का उपयोग करने की अनुमति देने के लिए।
- तर्कों को पूर्वनिर्धारित स्थानों में कॉपी करें, ताकि बुलाए गए फ़ंक्शन को यह पता चल सके कि यह कहाँ से कहा जाता है।
- रिटर्न एड्रेस को पुश करें।
- फ़ंक्शन के कोड में शाखा / कूद, जो एक संकलन-समय का पता है और इसलिए कंपाइलर / लिंकर द्वारा बाइनरी में हार्डकोड किया गया है।
- पूर्वनिर्धारित स्थान से वापसी मूल्य प्राप्त करें और उन रजिस्टरों को पुनर्स्थापित करें जिन्हें हम उपयोग करना चाहते हैं।
एक आभासी कॉल बिल्कुल एक ही काम करता है, सिवाय इसके कि फ़ंक्शन पता संकलन समय पर ज्ञात नहीं है। इसके बजाय, कुछ निर्देश ...
- वाइटटेबल पॉइंटर प्राप्त करें, जो कि ऑब्जेक्ट से प्रत्येक वर्चुअल फ़ंक्शन के लिए फ़ंक्शन पॉइंटर्स (फ़ंक्शन एड्रेस) की एक सरणी को इंगित करता है।
- व्यवहार्यता से सही फ़ंक्शन का पता एक रजिस्टर में प्राप्त करें (सूचकांक जहां सही फ़ंक्शन पता संग्रहीत है, संकलन-समय पर तय किया गया है)।
- किसी हार्डकोड किए गए पते पर जाने के बजाय उस रजिस्टर में पते पर जाएं।
शाखाओं के लिए के रूप में: एक शाखा कुछ भी है जो केवल अगले निर्देश को निष्पादित करने की बजाय एक और निर्देश के लिए कूदता है। इसमें शामिल हैं if
, switch
विभिन्न छोरों, फ़ंक्शन कॉल, आदि और कभी कभी संकलक लागू चीजें हैं जो नहीं है के कुछ हिस्सों के लिए एक रास्ता है कि वास्तव में हुड के नीचे एक शाखा की जरूरत में शाखा लगते हैं। देखें कि अनारक्षित सरणी की तुलना में एक सॉर्ट किए गए सरणी को तेज़ी से क्यों संसाधित किया जा रहा है? यह धीमा क्यों हो सकता है, सीपीयू इस मंदी का मुकाबला करने के लिए क्या करते हैं, और यह कैसे एक इलाज नहीं है।