2010-01-28 6 views
8

मैं मूलभूत रेफ-गिनती पॉइंटर क्लास से विरासत को शामिल करने वाला कुछ कोड लिख रहा हूं; और सी ++ की कुछ जटिलताओं को पॉप अप किया गया। इस प्रकार मैं इसे कम किया है:सी ++ पॉइंटर बहु-विरासत मज़े

मान लीजिए मैं:

class A{}; 
class B{}; 
class C: public A, public B {}; 

C c; 
C* pc = &c; 
B* pb = &c; 
A* pa = &c; 

// does pa point to a valid A object? 
// does pb point to a valid B object? 

// does pa == pb ? 

इसके अलावा, करता है:

// pc == (C*) pa ? 
// pc == (C*) pb ? 

धन्यवाद!

+2

आप == से क्या मतलब है? जाहिर है, पते एक ही हैं। –

+9

पते एक दूसरे के समान नहीं हैं। –

+1

मैंने जो एकाधिक विरासत (आभासी) देखा है, के एक कार्यान्वयन में, कुछ ऑफसेट बी के गुणों और विधियों तक पहुंचने के लिए व्युत्पन्न वर्ग के ऑब्जेक्ट के मूल पते में जोड़ा गया है। हालांकि यह उपयोगकर्ता के लिए दृश्यमान नहीं है क्योंकि संकलक आंतरिक रूप से इसका उपयोग करता है। इसलिए आपके कार्यक्रम में आप अभी भी देख सकते हैं कि ए, बी और सी का पता समान है। – mukeshkumar

उत्तर

7
  • क्या एक वैध ऑब्जेक्ट को इंगित करता है?
  • एक वैध बी वस्तु के लिए पीबी बिंदु करता है?

हाँ, C* ताकि परिवर्तित हो जाता है pa और सही पते पर pb बिंदु।

  • pa == pb करता है?

नहीं है, आम तौर पर नहीं। एक ही पते पर A ऑब्जेक्ट और B ऑब्जेक्ट नहीं हो सकता है।

इसके अलावा,

  • पीसी == (सी *) पा करता है?
  • पीसी == (सी *) पीबी?

डाली संकेत वापस C वस्तु का पता करने के लिए धर्मान्तरित, इसलिए दोनों समानताओं सही हैं।

+1

'dynamic_cast' यहां अनुचित है और सी-शैली सही है (हालांकि खराब फॉर्म)। §5.4/7 के अनुसार, सी-स्टाइल कास्टिंग एक 'static_cast'' कहला सकता है, जहां "गैर-वर्चुअल बेस क्लास प्रकार की ऑब्जेक्ट के लिए पॉइंटर, गैर वर्चुअल बेस क्लास प्रकार का एक आभासी, या गैर- वर्चुअल बेस क्लास प्रकार को क्रमशः एक व्युत्पन्न वर्ग प्रकार के सदस्य को सूचक, संदर्भ, या सूचक के रूप में परिवर्तित किया जा सकता है। " – Potatoswatter

+0

हाँ, आप सही हैं, गतिशील कलाकारों की केवल तभी आवश्यकता होगी यदि 'pa' को 'बी *' पर डाला जाएगा, उदाहरण के लिए। – sth

+0

उस स्थिति में, 'गतिशील_कास्ट' अभिव्यक्ति केवल 'NULL' कहने का एक शानदार तरीका होगा। एक ए * बी नहीं हो सकता है * इसलिए यह हमेशा असफल होगा। – Potatoswatter

1
pc == pa; 
pc == pb; 

परिभाषित नहीं किया गया है, वर्ग संरचना पर निर्भर करता है।

pc == (C*) pa; 
pc == (C*) pb; 

ठीक है।

pa == pb; 

सं

वे वैध वस्तुओं को इंगित करते हैं?

Yes 
2

C एक A और एक B एम्बेड करता है।

class C: public A, public B {}; 

बहुत सी कोड

struct C { 
    A self_a; 
    B self_b; 
}; 

और (B*) &c;static_cast< B* >(&c) के बराबर है के समान है &c.self_b के लिए इसी तरह अगर आप सीधे सी उपयोग कर रहे थे है

सामान्य रूप से, आप अलग-अलग प्रकारों को विनिमय करने योग्य या तुलनीय होने पर पॉइंटर्स पर भरोसा नहीं कर सकते हैं।

0

आपको क्या मिलेगा स्मृति में कुछ इस तरह है

---------- 
| A data | 
---------- 
| B data | 
---------- 
| C data | 
---------- 

तो तुम पूरे सी वस्तु आप स्मृति की शुरुआत करने के लिए एक सूचक मिल जाएगा चाहते हैं। यदि आप केवल ए "भाग" चाहते हैं, तो आपको वही पता मिलता है, जहां से डेटा सदस्य स्थित हैं। यदि आप बी "भाग" चाहते हैं तो आपको शुरुआत + आकार (ए) + आकार (जो भी कंपाइलर vtable के लिए जोड़ता है) प्राप्त करें। इस प्रकार, उदाहरण में, पीसी! = पीबी (पीसी हो सकता है! = पीए) लेकिन पी पीबी के बराबर कभी नहीं है।

+1

मैं 'पीसी! = पीबी' पर अलग होना चाहता हूं। DevStudio 2005 में प्रश्न कोड को टाइप करते हुए, मुझे एक ही मूल्य के साथ सभी पॉइंटर्स मिलते हैं। और शायद यही कारण है कि सी ++ मानक कहता है कि इस मामले में - कोई आभासी तरीकों और कोई डेटा सदस्य नहीं हैं। ओपी ने एक और सवाल पोस्ट किया है जहां बेस क्लास के पास सदस्य हैं, इसलिए इसका एक अलग उत्तर है, जो यह उत्तर कम या ज्यादा है। – Skizz

+0

@ स्किज़: जो आप देख रहे हैं उसे खाली बेस क्लास ऑप्टिमाइज़ेशन कहा जाता है http://www.google.com/search?q=empty+base+class+optimization यह सभी आधुनिक कंपाइलर्स द्वारा कार्यान्वित किया गया है लेकिन इसकी आवश्यकता होने से बहुत दूर है। – Potatoswatter

+1

कक्षा ए {}; कक्षा बी {}; कक्षा सी: सार्वजनिक ए, सार्वजनिक बी {}; int मुख्य() { सी सी; सी * पीसी (&c); ए * पीए (पीसी); बी * पीबी (पीसी); printf ("सी = 0x% 08X \ nB = 0x% 08X \ nA = 0x% 08X \ n", पीसी, पीबी, पी) ; } VS2008 रिलीज से उत्पादन का निर्माण सी = 0x0018FEFF बी = 0x0018FF00 एक = 0x0018FEFF आप जिस क्रम में सी ए और बी से विरासत बदलते हैं तो आप ए और बी के लिए अलग मान मिलेगा –

0

C++ Common Knowledge: Essential Intermediate Programming में Item 28 Meaning of Pointer Comparison) सी में वस्तु सूचक के प्रमुख बताते हैं ++:

सी ++ में, एक वस्तु से अधिक, मान्य पतों के हो सकते हैं, और सूचक तुलना पते के बारे में सवाल नहीं है। यह वस्तु पहचान के बारे में एक सवाल है।

कोड पर एक नज़र डालें:

class A{}; 
class B{}; 
class C: public A, public B {}; 

C c; 
C* pc = &c; 
B* pb = &c; 
A* pa = &c; 

class Cclass A और class B दोनों से निकला है, इसलिए class Cclass A और class B दोनों है। ऑब्जेक्ट C c में 3 मान्य पते हैं: class A, class B और class C के लिए पता। कार्यान्वयन संकलक पर निर्भर करता है, तो आप class C की स्मृति लेआउट कल्पना नहीं कर सकते हैं, और यह इस तरह हो सकता है:

---------- <- pc (0x7ffe7d10e1e0) 
|  | 
---------- <- pa (0x7ffe7d10e1e4) 
| A data | 
---------- <- pb (0x7ffe7d10e1e8) 
| B data | 
---------- 
| C data | 
---------- 

उपरोक्त मामले में, हालांकि pc, pa और pb का पता मूल्य ही नहीं हैं, वे सभी एक ही ऑब्जेक्ट (c) का संदर्भ लेते हैं, इसलिए संकलक को यह सुनिश्चित करना चाहिए कि pcpa और pb, यानी pc == pa और pc == pb दोनों के बराबर तुलना करता है। कंपाइलर उचित ऑफसेट की तुलना में पॉइंटर्स में से किसी एक के मूल्य को समायोजित करके इस तुलना को पूरा करता है। जैसे,

pc == pa 

लिए अनुवाद किया है: A के बाद से

pc ? ((uintptr_t)pc + 4 == (uintptr_t)pa) : (pa == 0) 

अन्य बातों के अलावा, और B कोई विरासत रिश्ता है, हम pa और pb सीधे तुलना नहीं कर सकते।

अपने प्रश्नों के लिए:

(1) does pa point to a valid A object? 
(2) does pb point to a valid B object? 
Yes, refer the above diagram. 

(3) pc == (C*) pa ? 
(4) pc == (C*) pb ? 
Yes, No need to add (C*). 

(5) does pa == pb ? 
No. We can't compare them. 
संबंधित मुद्दे