मैं @sechastain
से असहमत हूं।
इनलाइनिंग स्वचालित होने से बहुत दूर है। विधि या संकेत (inline
कीवर्ड या __forceinline
) में विधि को परिभाषित किया गया है या नहीं, इसका उपयोग किया जाता है, यह तय करने के लिए संकलक केवल एकमात्र है कि इनलाइनिंग वास्तव में होगी या नहीं, और ऐसा करने के लिए जटिल हेरिस्टिक का उपयोग करता है। हालांकि, एक विशेष मामला यह है कि जब रनटाइम प्रेषण का उपयोग करके वर्चुअल विधि का आह्वान किया जाता है तो यह कॉल को इनलाइन नहीं करेगा, ठीक है क्योंकि रनटाइम प्रेषण और इनलाइनिंग संगत नहीं है।
IClassInterface* i = /**/;
i->LOL(); // runtime dispatch
i->QueueClass::LOL(); // compile time dispatch, inline is possible
@0xDEAD BEEF
:
"क्रम प्रेषण का उपयोग कर" की शुद्धता को समझने के लिए मैं अपने डिजाइन कम से कम कहने के लिए भंगुर पाते हैं।
सी-शैली के उपयोग यहाँ डाले गलत है:
QueueClass* p = /**/;
IClassInterface* q = p;
assert(((void*)p) == ((void*)q)); // may fire or not...
मूलरूप कोई गारंटी नहीं कि 2 पतों बराबर हैं है: यह कार्यान्वयन परिभाषित है, और परिवर्तन का विरोध करने की संभावना नहीं है।
मैं तुम्हें तो आप एक IClassInterface*
से उसे बनाने के लिए मूल रूप से इतना है कि सी ++ संकलक वस्तुओं के लेआउट पर निर्भर सही सूचक अंकगणित प्रदर्शन कर सकते हैं की जरूरत है सुरक्षित रूप से एक IClassInterface*
सूचक को void*
सूचक कास्ट करने के लिए सक्षम होने के लिए चाहते हैं।
बेशक, मैं वैश्विक चर के उपयोग की तुलना में भी रेखांकित करूँगा ... आप शायद इसे जानते हैं।
अनुपस्थिति के कारण के रूप में? मैं ईमानदारी से कंपाइलर/लिंकर में एक बग से अलग नहीं देखता हूं। मैंने virtual
की अंतर्निहित परिभाषा को कुछ बार देखा है (अधिक विशेष रूप से, clone
विधि) और इससे कभी भी समस्याएं नहीं हुईं।
संपादित: चूंकि "सही सूचक अंकगणित" इतनी अच्छी तरह से समझा नहीं गया था, यहां एक उदाहरण
struct Base1 { char mDum1; };
struct Base2 { char mDum2; };
struct Derived: Base1, Base2 {};
int main(int argc, char* argv[])
{
Derived d;
Base1* b1 = &d;
Base2* b2 = &d;
std::cout << "Base1: " << b1
<< "\nBase2: " << b2
<< "\nDerived: " << &d << std::endl;
return 0;
}
यहाँ है और क्या छपा था है:
Base1: 0x7fbfffee60
Base2: 0x7fbfffee61
Derived: 0x7fbfffee60
नहीं के बीच का अंतर b2
और &d
का मान, भले ही वे एक इकाई का संदर्भ लें। यह समझा जा सकता है अगर कोई ऑब्जेक्ट के मेमोरी लेआउट के बारे में सोचता है।
Derived
Base1 Base2
+-------+-------+
| mDum1 | mDum2 |
+-------+-------+
जब Base2*
को Derived*
से परिवर्तित, संकलक (एक बाइट द्वारा सूचक पता यहाँ, बढ़ाने के) आवश्यक समायोजन प्रदर्शन करेंगे ताकि सूचक को प्रभावी ढंग से Derived
की Base2
भाग की ओर इशारा करते समाप्त होता है और के लिए नहीं Base1
भाग को गलती से Base2
ऑब्जेक्ट (जो कि बुरा होगा) के रूप में व्याख्या की गई है।
यही कारण है कि डाउनकास्टिंग के दौरान सी-स्टाइल कास्ट का उपयोग करना टालना चाहिए। यहां, यदि आपके पास Base2
पॉइंटर है तो आप इसे Derived
पॉइंटर के रूप में पुन: परिभाषित नहीं कर सकते हैं। इसके बजाय, आपको static_cast<Derived*>(b2)
का उपयोग करना होगा जो सूचक को एक बाइट द्वारा कम करेगा ताकि यह सही ढंग से Derived
ऑब्जेक्ट की शुरुआत को इंगित करे।
मैनिपुलेटिंग पॉइंटर्स को आमतौर पर पॉइंटर अंकगणित के रूप में जाना जाता है। यहां कंपाइलर स्वचालित रूप से प्रकार के बारे में जागरूक होने की स्थिति पर सही समायोजन करेगा।
दुर्भाग्यवश संकलक void*
से कनवर्ट करते समय उन्हें निष्पादित नहीं कर सकते हैं, यह इस प्रकार डेवलपर को यह सुनिश्चित करने के लिए है कि वह सही ढंग से इसे संभालता है। अंगूठे का सरल नियम निम्न है: T* -> void* -> T*
दोनों पक्षों पर दिखाई देने वाले एक ही प्रकार के साथ।
इसलिए, आपको घोषित करके अपने कोड को सही (सही) करना चाहिए: IClassInterface* globalMember
और आपके पास कोई पोर्टेबिलिटी समस्या नहीं होगी। आपके पास अभी भी रखरखाव समस्या होगी, लेकिन ओओ-कोड के साथ सी का उपयोग करने की समस्या है: सी किसी ऑब्जेक्ट उन्मुख सामग्री के बारे में पता नहीं है।
'क्यूई क्लास' (यदि कोई है तो) में किसी अन्य गैर-इनलाइन वर्चुअल फ़ंक्शंस के बारे में क्या? क्या वे कार्य करते हैं? दूसरे शब्दों में, 'एलओएल' स्थानीय 'एलओएल की वीटेबल एंट्री' के साथ मुद्दा है या पूरा वीटीई खाली या गायब है? – AnT
आईसीएलएएस इंटरफेस से निजी तौर पर क्यों उत्तराधिकारी है? –
'आईसीएलएएस इंटरफेस *' के बजाय 'शून्य ...' फ़ंक्शन 'शून्य *' क्यों लौटा रहा है? – AnT