आपके उदाहरण में, आपके आउटपुट की अपेक्षा की जा सकती है। Virtual inheritance
उदाहरण में खेलता है जब आपके पास एकाधिक विरासत वाले वर्ग होते हैं, जिनके माता-पिता वर्ग भी उसी वर्ग/प्रकार (यानी "हीरा समस्या") से प्राप्त होते हैं। आपके उदाहरण में, आपकी कक्षाओं को वर्चुअल रूप से प्राप्त करने के लिए सेट किया जा सकता है (यदि कोड में कहीं और आवश्यक है), लेकिन वे आपके उदाहरण के आधार पर 'वर्चुअल वारिस' जरूरी नहीं हैं क्योंकि व्युत्पन्न कक्षाओं में से कोई भी नहीं (B1/B2/C1/C2
) सीधे प्राप्तकर्ता से अधिक करता है A
से।
का विस्तार करने के लिए, मैं अपने उदाहरण बदलाव किया है थोड़ा और व्याख्या करने के लिए:
#include <cstdio>
#define tracefunc printf(__FUNCTION__); printf("\r\n")
struct A
{
A() { tracefunc; }
virtual void write() { tracefunc; }
virtual void read() { tracefunc; }
};
struct B1 : public A
{
B1() { tracefunc; };
void read(){ tracefunc; }
};
struct C1 : public A
{
C1() { tracefunc; };
void write(){ tracefunc; }
};
struct B2 : virtual public A
{
B2() { tracefunc; };
void read(){ tracefunc; }
};
struct C2 : virtual public A
{
C2() { tracefunc; };
void write(){ tracefunc; }
};
// Z1 inherits from B1 and C1, both of which inherit from A; when a call is made to any
// of the base function (i.e. A::read or A::write) from the derived class, the call is
// ambiguous since B1 and C1 both have a 'copy' (i.e. vtable) for the A parent class.
struct Z1 : public B1, public C1
{
Z1() { tracefunc; }
};
// Z2 inherits from B2 and C2, both of which inherit from A virtually; note that Z2 doesn't
// need to inherit virtually from B2 or C2. Since B2 and C2 both virtual inherit from A, when
// they are constructed, only 1 copy of the base A class is made and the vtable pointer info
// is "shared" between the 2 base objects (B2 and C2), and the calls are no longer ambiguous
struct Z2 : public B2, public C2
{
Z2() { tracefunc; }
};
int _tmain(int argc, _TCHAR* argv[])
{
// gets 2 "copies" of the 'A' base since 'B1' and 'C1' don't virtually inherit from 'A'
Z1 z1;
// gets only 1 "copy" of 'A' base since 'B2' and 'C2' virtualy inherit from 'A' and thus "share" the vtable pointer to the 'A' base
Z2 z2;
z1.write(); // ambiguous call to write (which one is it .. B1::write() (since B1 inherits from A) or A::write() ?)
z1.read(); // ambiguous call to read (which one is it .. C1::read() (since C1 inherits from A) or A::read() ?)
z2.write(); // not ambiguous: z2.write() calls C2::write() since it's "virtually mapped" to/from A::write()
z2.read(); // not ambiguous: z2.read() calls B2::read() since it's "virtually mapped" to/from A::read()
return 0;
}
यह हमें मनुष्य जो फोन हम z1
चर के मामले में करने का इरादा करने के लिए "स्पष्ट" हो सकती है, चूंकि B1
में write
विधि नहीं है, तो मैं संकलक को C1::write
विधि चुनने की अपेक्षा करता हूं, लेकिन ऑब्जेक्ट्स की मेमोरी मैपिंग कैसे काम करती है, यह C1
ऑब्जेक्ट में A
की मूल प्रतिलिपि के कारण समस्या उत्पन्न करती है B1
ओबीजे में A
आधार की प्रति से अलग जानकारी (पॉइंटर्स/संदर्भ/हैंडल) ect (चूंकि तकनीकी रूप से A
आधार की 2 प्रतियां हैं); इस प्रकार B1::read() { this->write(); }
पर एक कॉल अप्रत्याशित व्यवहार दे सकता है (हालांकि अपरिभाषित नहीं)।
virtual
बेस क्लास विनिर्देशक पर कीवर्ड यह स्पष्ट करता है कि अन्य वर्ग जो समान आधार प्रकार से प्राप्त होते हैं, केवल मूल प्रकार की 1 प्रति प्राप्त करेंगे।
ध्यान दें कि उपर्युक्त कोड z1
ऑब्जेक्ट के लिए संदिग्ध कॉल समझाते हुए संकलक त्रुटियों के साथ संकलित करने में विफल होना चाहिए। ,
A::A
B1::B1
A::A
C1::C1
Z1::Z1
A::A
B2::B2
C2::C2
Z2::Z2
C2::write
B2::read
नोट 2 Z1
से पहले A
ctor (A::A
) के लिए कॉल का निर्माण किया है, जबकि Z2
केवल 1 कॉल है: आप z1.write();
और z1.read();
लाइनों उत्पादन बाहर टिप्पणी है (मेरे लिए कम से कम) निम्नलिखित है A
कन्स्ट्रक्टर के लिए।
मैं the following on virtual inheritance पढ़ने की अनुशंसा करता हूं क्योंकि यह ध्यान देने के लिए कुछ अन्य दोषों पर गहराई से अधिक जाता है (इस तथ्य की तरह कि वर्चुअल विरासत वाले वर्गों को बेस क्लास सीटीओआर कॉल करने के लिए प्रारंभिक सूची का उपयोग करने की आवश्यकता है, या आपको टालना चाहिए इस प्रकार की विरासत करते समय सी-शैली का उपयोग करता है)।
यह कन्स्ट्रक्टर/विनाशक आदेश के साथ शुरू में जो कुछ भी शुरू कर रहा था, उससे थोड़ा और बताता है, और अधिक विशेष रूप से एकाधिक आभासी विरासत का उपयोग करते समय ऑर्डरिंग कैसे की जाती है।
आशा है कि चीजों को थोड़ा सा साफ़ करने में मदद कर सकते हैं।
आपने क्या उम्मीद की थी? "दादी" हमेशा पहले बुलाया जाता है। इससे कोई फर्क नहीं पड़ता कि आप किस प्रकार की विरासत का उपयोग कर रहे हैं। यदि यह अलग था तो निम्न स्तर की कक्षाओं ने अपने रचनाकारों में माता-पिता के डेटा का उपयोग कैसे किया? – ixSci
आभासी विरासत केवल एकाधिक विरासत के मामले में अंतर बनाती है। यह विरासत ग्राफ के माध्यम से कुछ संरचना साझा करने के लिए प्रदान किया जाता है। –