दिलचस्प पोस्ट
कई अनुप्रयोगों को स्थापित करने के लिए Wix यूनिडायरेक्शनल एक को कई एसोसिएशन में हाइबरनेट करें – क्यों शामिल होना बेहतर तालिका है? कुछ यूनिकोड वर्ण std :: wcout को कन्सोल ऐप में विफल होने के कारण क्यों हैं? कस्टम फ़्रेम में Array.prototype जोड़ना OSX Yosemite को "अपग्रेड करने" के बाद RStudio / R में आरजावा लोड त्रुटि Sed का उपयोग कर एक स्ट्रिंग वाली पूरी रेखा को बदलें चेनिंग .bind () जावास्क्रिप्ट में कॉल अप्रत्याशित परिणाम? संपत्ति के नाम के रूप में आरक्षित शब्द का उपयोग करके, पुनरीक्षित किया गया डीडी में सी # में पासवर्ड रखने के लिए नमक के साथ एमडी 5 हैश कैसे हैंडी फ़ंक्शन MD5 अद्वितीय हैं? मैं ANTLR4 का उपयोग कर एक एएसटी कैसे बना सकता हूं? लंबे समय तक विस्तृत प्रारूप में डेटा कैसे आकार देना है? इंटेंट्स का इस्तेमाल एंड्रॉइड में गतिविधियों के बीच डेटा पास करने के लिए करना मैं TabControl के अंदर एक टैब कैसे अक्षम कर सकता हूं? गतिविधियों के बीच वस्तुओं की सरणी सूची

सी ++ डेटा संरेखण / सदस्य आदेश और विरासत

अगर वंशानुक्रम / एकाधिक वंशानुगतों का उपयोग किया जाता है तो डेटा के सदस्यों को कैसे गठबंधन / आदेश दिया जाता है? क्या यह संकलक विशिष्ट है?

क्या व्युत्पन्न वर्ग में निर्दिष्ट करने का एक तरीका है कि कैसे सदस्यों (आधार वर्ग के सदस्यों सहित) के आदेश / संरेखित किए जाएंगे?

धन्यवाद!

Solutions Collecting From Web of "सी ++ डेटा संरेखण / सदस्य आदेश और विरासत"

वास्तव में आप बहुत सारे अलग-अलग प्रश्न पूछ रहे हैं, इसलिए मैं हर एक के बदले उत्तर देने के लिए अपनी पूरी कोशिश कर रहा हूं।

सबसे पहले आप यह जानना चाहते हैं कि डेटा के सदस्य गठबंधन कैसे कर रहे हैं। सदस्य संरेखण कंपाइलर परिभाषित किया गया है, लेकिन सीपीयू गलत तरीके से डेटा के साथ कैसे निपटता है, इसकी वजह से, वे सभी समान का पालन करते हैं

दिशानिर्देश यह है कि संरचनाएं सबसे अधिक प्रतिबंधात्मक सदस्य (जो आमतौर पर, हमेशा की तरह सबसे बड़ी आंतरिक प्रकार के आधार पर) के आधार पर गठबंधन की जानी चाहिए, और स्ट्रुक्टार्स हमेशा गठबंधन कर रहे हैं, क्योंकि सरणी के तत्व सभी समान रूप से गठबंधन करते हैं।

उदाहरण के लिए:

 struct some_object { char c; double d; int i; }; 

यह संरचना 24 बाइट्स होगा। क्योंकि कक्षा में एक डबल है, यह 8 बाइट संरेखित हो जाएगा, जिसका अर्थ है कि चार बाइट्स के द्वारा चार गढ़ा होगा, और int को 4 द्वारा गद्देदार किया जाएगा यह सुनिश्चित करने के लिए कि some_object की एक सरणी में, सभी तत्व 8 बाइट संरेखित होंगे। सामान्यतया यह संकलक निर्भर है, यद्यपि आप पाएंगे कि किसी दिए गए प्रोसेसर आर्किटेक्चर के लिए, अधिकांश कंपाइलर्स डेटा को समान रूप से संरेखित करते हैं।

दूसरी चीज जिसका आप उल्लेख करते हैं वह क्लास सदस्यों से व्युत्पन्न होता है। व्युत्पन्न कक्षाओं का क्रम और संरेखण थोड़े दर्द है। क्लासेस अलग-अलग नियमों का पालन करते हैं जिन्हें मैं स्ट्रेंक्ट्स के लिए ऊपर वर्णित करता हूं, लेकिन जब आप विरासत के बारे में बात करना शुरू करते हैं तो आप गन्दा मैदान में आ जाते हैं। निम्नलिखित वर्गों को देखते हुए:

 class base { int i; }; class derived : public base // same for private inheritance { int k; }; class derived2 : public derived { int l; }; class derived3 : public derived, public derived2 { int m; }; class derived4 : public virtual base { int n; }; class derived5 : public virtual base { int o; }; class derived6 : public derived4, public derived5 { int p; }; 

आधार के लिए स्मृति लेआउट होगा:

 int i // base 

व्युत्पन्न के लिए स्मृति लेआउट होगा:

 int i // base int k // derived 

व्युत्पन्न 2 के लिए मेमोरी लेआउट होगा:

 int i // base int k // derived int l // derived2 

व्युत्पन्न 3 के लिए स्मृति लेआउट होगा:

 int i // base int k // derived int i // base int k // derived int l // derived2 int m // derived3 

आप ध्यान दें कि आधार और व्युत्पन्न प्रत्येक को दो बार दिखाई देगा। यह कई विरासत का आश्चर्य है

चारों ओर पाने के लिए कि हमारे पास आभासी विरासत है

व्युत्पन्न 4 के लिए स्मृति लेआउट होगा:

 base* base_ptr // ptr to base object int n // derived4 int i // base 

व्युत्पन्न 5 के लिए स्मृति लेआउट होगा:

 base* base_ptr // ptr to base object int o // derived5 int i // base 

व्युत्पन्न 6 के लिए मेमोरी लेआउट होगा:

 base* base_ptr // ptr to base object int n // derived4 int o // derived5 int i // base 

आप ध्यान दें कि व्युत्पन्न 4, 5, और 6 के सभी आधार ऑब्जेक्ट के लिए एक सूचक है। यह न्यूसीसरी है ताकि बेस के किसी भी कार्य को बुलाते समय उन कार्यों को पारित करने के लिए एक ऑब्जेक्ट हो। यह संरचना कंपाइलर निर्भर है क्योंकि यह भाषा युक्ति में निर्दिष्ट नहीं है, लेकिन लगभग सभी कंपाइलर्स इसे एक ही लागू करते हैं।

जब आप वर्चुअल फ़ंक्शन के बारे में बात करना शुरू करते हैं, लेकिन फिर भी, अधिकतर संकलक उन्हें समान रूप से लागू करते हैं, तो हालात अधिक जटिल होते हैं। निम्नलिखित कक्षाएं लें:

 class vbase { virtual void foo() {}; }; class vbase2 { virtual void bar() {}; }; class vderived : public vbase { virtual void bar() {}; virtual void bar2() {}; }; class vderived2 : public vbase, public vbase2 { }; 

इनमें से प्रत्येक वर्ग में कम से कम एक वर्चुअल फ़ंक्शन शामिल है।

Vbase के लिए स्मृति लेआउट होगा:

 void* vfptr // vbase 

Vbase2 के लिए स्मृति लेआउट होगा:

 void* vfptr // vbase2 

Vderived के लिए स्मृति लेआउट होगा:

 void* vfptr // vderived 

Vderived2 के लिए स्मृति लेआउट होगा:

 void* vfptr // vbase void* vfptr // vbase2 

कई चीजें हैं जो लोगों को इसके बारे में नहीं पता है कि कैसे vftables काम करते हैं समझने वाली पहली बात यह है कि कक्षाएं केवल संकेतक को केवल vftables के लिए स्टोर करती हैं, संपूर्ण vftables नहीं

इसका मतलब यह है कि कोई भी वर्ग कितने वर्चुअल फ़ंक्शंस का कोई फर्क नहीं पड़ता है, यह केवल एक vftable होगा, जब तक कि उसे कई विरासत के माध्यम से कहीं और से vftable नहीं मिलेगा बहुत सारे सभी कंपाइलर्स ने कक्षा के बाकी सदस्यों से पहले vftable पॉइंटर डाल दिया। इसका मतलब है कि आपके पास vftable सूचक और वर्ग के सदस्यों के बीच कुछ पैडिंग हो सकते हैं

मैं आपको यह भी बता सकता हूं कि लगभग सभी कंपलर्स प्रोगा पैक क्षमताओं को लागू करते हैं जो आपको संरचना संरेखण को मैन्युअल रूप से बल देने की अनुमति देते हैं। आम तौर पर आप ऐसा नहीं करना चाहते हैं जब तक कि आप वास्तव में नहीं जानते कि आप क्या कर रहे हैं, लेकिन यह वहां है, और कभी-कभी यह नर्किसरी है।

आखिरी चीज जिसे आपने पूछा है, अगर आप ऑर्डर को नियंत्रित कर सकते हैं आप हमेशा आदेश को नियंत्रित करते हैं कंपाइलर हमेशा उन चीजों को ऑर्डर करेगा, जो आप उन्हें लिखते हैं। मुझे उम्मीद है कि यह लंबे समय से चलने वाली स्पष्टीकरण आपको जो कुछ भी जानने की जरूरत है, उसे हिट करता है।

यह सिर्फ संकलक विशिष्ट नहीं है – यह संकलक विकल्प से प्रभावित होने की संभावना है। मैं किसी भी कंपाइलर के बारे में नहीं जानता हूं, जिस पर आप कितने सदस्यों और ठिकानों को पैक कर सकते हैं और कितने वंशानुक्रमों के साथ आदेश दिया जाता है, इस पर आपको अच्छा दानेदार नियंत्रण प्रदान करते हैं।

यदि आप कुछ ऐसा कर रहे हैं जो ऑर्डर और पैकिंग पर निर्भर करता है, तो अपने क्लास के अंदर एक पॉड स्टोरी को संचित करने और उस का उपयोग करने का प्रयास करें।

यह संकलक विशिष्ट है

संपादित करें: मूल रूप से यह आती है कि वर्चुअल तालिका कहाँ पर रखी गई है और यह उस कम्पाइलर के उपयोग के आधार पर अलग-अलग हो सकता है।

जैसे ही आपका क्लास पीओडी (सादा पुराना डेटा) नहीं है, सभी दांव बंद हैं I संभवतः संकलक-विशिष्ट निर्देश हैं जो आप डेटा पैक / संरेखित करने के लिए उपयोग कर सकते हैं।

कम्पाइलर आमतौर पर स्ट्रक्क्ट्स में डेटा सदस्यों को आसान पहुंच के लिए अनुमति देते हैं। इसका अर्थ है कि डेटा तत्व आमतौर पर शब्द सीमाओं पर शुरू होंगे और यह सामान्य रूप से एक स्ट्रैट में छोड़ दिया जाएगा ताकि यह सुनिश्चित हो सके कि शब्द सीमाएं गठबंधन नहीं हैं।

इसलिए

 struct foo
 {
     चार ए;
     int b;
     चार सी;
 }

आम तौर पर एक 32 बिट मशीन के लिए 6 बाइट्स से अधिक ले जाएगा

बेस क्लास को सामान्यतः पहले और व्युत्पन्न वर्ग के आधार पर लगाया जाता है, जिसे आधार वर्ग के बाद रखा गया था। यह आधार वर्ग के पते को व्युत्पन्न वर्ग के पते के बराबर की अनुमति देता है।

कई विरासत में एक वर्ग के पते और दूसरे आधार वर्ग के पते के बीच ऑफसेट होता है। >static_cast और dynamic_cast ऑफ़सेट की गणना करेगा reinterpret_cast नहीं करता है यदि सी संभव हो तो सी स्टाइल एक स्टैटिक कास्ट करता है, अन्यथा कोई पुन: प्रतिलिपि कास्ट।

जैसा कि अन्य लोगों ने उल्लेख किया है, यह सब संकलक विशिष्ट है, लेकिन उपरोक्त आपको सामान्यतः क्या होता है के लिए एकदम सही गाइड देना चाहिए।

कई विरासत में वस्तुओं का क्रम हमेशा आपके द्वारा निर्दिष्ट नहीं होता है। मैंने जो कुछ अनुभव किया है, से कंपाइलर निर्दिष्ट क्रम का उपयोग करेगा, जब तक कि वह नहीं कर सके। यह निर्दिष्ट आदेश का उपयोग नहीं कर सकता जब पहले बेस क्लास में वर्चुअल फ़ंक्शंस नहीं होता है और अन्य बेस क्लास में आभासी फ़ंक्शन होते हैं। इस मामले में, कक्षा के पहले बाइट्स को वर्चुअल फंक्शन टेबल पॉइंटर होना चाहिए, लेकिन पहले बेस क्लास में एक नहीं है। कंपाइलर मूल कक्षाओं को पुनर्व्यवस्थित करेगा ताकि पहले एक में एक वर्चुअल फंक्शन टेबल पॉइंटर हो।

मैंने इसे msdev और g ++ दोनों के साथ परीक्षण किया है और दोनों ही कक्षाओं को पुनर्व्यवस्थित करते हैं कष्टप्रद रूप से, उन्हें लगता है कि वे यह कैसे करते हैं के लिए अलग-अलग नियम हैं। यदि आपके पास 3 या अधिक आधार वर्ग हैं और सबसे पहले कोई वर्चुअल फ़ंक्शन नहीं है, तो इन कंपलर विभिन्न लेआउट के साथ आएंगे।

सुरक्षित होने के लिए, दो चुनें और दूसरे से बचें

  1. एकाधिक विरासत का उपयोग करते समय आधार वर्गों के आदेश पर भरोसा मत करो।

  2. जब बहुआयामी विरासत का उपयोग करते हुए, वर्चुअल फ़ंक्शन के बिना किसी भी बेस क्लास से पहले आभासी फ़ंक्शंस के साथ सभी बेस क्लास डालते

  3. 2 या उससे कम आधार वर्गों का उपयोग करें (चूंकि कम्पाइलर्स दोनों इस मामले में एक ही तरीके से पुनर्व्यवस्थित होते हैं)

सभी कंपाइलर मुझे पता है कि मूल वर्ग के ऑब्जेक्ट को एक व्युत्पन्न क्लास ऑब्जेक्ट में डेटा सदस्यों से पहले रखा गया है। डेटा के सदस्यों को क्रम के अनुसार वर्गीकृत किया जाता है। संरेखण के कारण अंतराल हो सकता है मैं यह नहीं कह रहा हूं कि यह इस तरह से होना चाहिए, हालांकि।

मैं एक सवाल का जवाब दे सकता हूं

अगर वंशानुक्रम / एकाधिक वंशानुगतों का उपयोग किया जाता है तो डेटा के सदस्यों को कैसे गठबंधन / आदेश दिया जाता है?

मैंने कक्षाओं के स्मृति लेआउट, फ़्रेम के फ़्रेम और अन्य एबीआई सूचना (लिनक्स, जीसीसी) को देखने के लिए एक उपकरण बनाया है। आप mysqlpp :: कनेक्शन क्लास के लिए परिणाम को देख सकते हैं (MySQL ++ लाइब्रेरी से वैकल्पिक विकल्प प्राप्त कर सकते हैं)

यहां छवि विवरण दर्ज करें