2013-01-22 50 views
6

मैं एक प्रकार पदानुक्रम में निर्माताओं के लिए नियमों बुला के साथ एक मुश्किल समय हो रही है। (निर्माता कॉल पदानुक्रम

class A{ 
protected: 
    int _i; 
public: 
    A(){i = 0;} 
    A(int i) : _i(i){} 
    virtual ~A(){} 
    virtual void print(){std::cout<<i<<std::endl;} 
}; 

class B : virtual public A{ 
protected: 
    int _j; 
public: 
    B() : A(){_j = 0;} 
    B(int i, int j) : A(i), _j(j){} 
    virtual ~B(){} 
    virtual void print(){std::cout<<i<<", "<<j<<std::endl;} 
}; 

class C : virtual public B{ 
protected: 
    int _k; 
public: 
    C() : B(){_k = 0;} 
    C(int i, int j, int k} : B(i,j), _k(k){} 
    virtual ~C(){} 
    virtual void print(){std::cout<<i<<", "<<j<<", "<<k<<std::endl;} 
}; 

int main(){ 
    C* myC = new C(1,2,3); 
    myC->print(); 
    delete myC; 
    return 0; 
} 

अब, मैं नई सी (1,2,3) बी (1,2) के निर्माता फोन जो तब बदले में निर्माता एक फोन करना चाहिए करना चाहते हैं 1: यहाँ मैं क्या कर रहा है) _i = 1, _j = 2, _k = 3 स्टोर करने के लिए। कक्षा सी के उदाहरण आईसी बनाते समय, किसी कारण से मुझे समझ में नहीं आता है, हालांकि, पहले कन्स्ट्रक्टर को कॉल करने के लिए मानक कन्स्ट्रक्टर ए, यानी ए :: ए(); यह स्पष्ट रूप से गलत परिणाम की ओर जाता है, क्योंकि संरक्षित चर _i को मान 0 असाइन किया गया है। कन्स्ट्रक्टर ए (1) कभी नहीं कहा जाता है। ऐसा क्यों है? मुझे यह बहुत काउंटर अंतर्ज्ञानी लगता है। वांछित व्यवहार प्राप्त करने के लिए टाइप-पदानुक्रम के भीतर सभी रचनाकारों को स्पष्ट रूप से कॉल करने से बचने का कोई तरीका है?

सहायता के लिए Thx!

+0

इस तरह के उत्तरों के लिए Thx। तो, मुझे लगता है कि मैं वर्चुअल विरासत की अवधारणा को फिर से पढ़ने के लिए स्ट्रॉस्ट्रप पर वापस जाऊंगा। ऐसा लगता है कि इसे डिफ़ॉल्ट रूप से उपयोग करना बुद्धिमान नहीं है;) – user1999920

+0

कई लोग सोचते हैं कि विरासत डिफ़ॉल्ट रूप से वर्चुअल क्यों नहीं है। खैर, आपको अपने आप से जवाब मिल गया है :) – Gorpik

उत्तर

5

जब आप आभासी विरासत का उपयोग करें, सबसे व्युत्पन्न वर्ग अपने सभी आभासी सीधे अड्डों के लिए कंस्ट्रक्टर कॉल करना होगा। इस मामले में, C के लिए निर्माता को B और A के लिए निर्माता को कॉल करना होगा। चूंकि आप केवल B कन्स्ट्रक्टर को कॉल करते हैं, यह डिफ़ॉल्ट A कन्स्ट्रक्टर का उपयोग करता है। इससे कोई फर्क नहीं पड़ता कि B कन्स्ट्रक्टर अन्य A कन्स्ट्रक्टर कहता है: चूंकि यह वर्चुअल बेस क्लास है, इसलिए इस कॉल को अनदेखा किया जाता है। स्पष्ट रूप से A(int) निर्माता फोन:

आप इस समस्या को हल दो तरीके हैं

C(int i, int j, int k} : A (i), B(i,j), _k(k){} 

या आभासी के बजाय सामान्य विरासत का उपयोग करें।

+1

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

+0

@ चार्ल्सबैली मेरे जवाब को दोबारा पढ़ना, आप सही हैं: मैंने सही ढंग से यह समझाया नहीं है (कि * स्पष्ट रूप से * भ्रामक है)। मैं इसे ठीक कर रहा हूँ। – Gorpik

6

इसका कारण यह है कि आप आभासी विरासत, जो कई विरासत की उपस्थिति में ही समझ में आता है इस्तेमाल किया। बस सामान्य रूप से वारिस करें, और जैसा कि आप उम्मीद करेंगे उतना ही होगा।

+0

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

+0

@JamesKanze, यह गलत है, आप नहीं करते यदि आप आम पूर्वजों वाले 2+ वर्गों से एकाधिक विरासत नहीं कर रहे हैं तो वर्चुअल विरासत की आवश्यकता है। इसके अलावा, आप वर्चुअल विरासत के बिना एकाधिक इंटरफेस को कार्यान्वित कर सकते हैं: उदाहरण के लिए COM देखें। – Steed

+0

मुझे लगता है कि मुझे "इंटरफ़ेस" की आपकी परिभाषा नहीं मिली है। क्या आपका मतलब जावा प्रकार का इंटरफेस है (यानी सदस्यों के बिना एक अमूर्त वर्ग)? हालांकि, मैंने सी ++ में कई प्रकार की चीजें देखी हैं, जो एक इनिनेफेस कह सकती हैं, लेकिन उनमें से कोई भी वर्चुअल विरासत की आवश्यकता नहीं है। बेशक, कुछ परिस्थितियों में अमूर्त वर्ग कई विरासत ग्राफों में उलझ जाते हैं, लेकिन चूंकि उनके पास कोई सदस्य नहीं है, क्या वर्चुअल वर्चुअल विरासत के बिना भी काम नहीं करना चाहिए? –

7

तुम सच में यहाँ एक virtual विरासत की ज़रूरत है? आप एक समस्या मिल गया है क्योंकि एक बहुत पहले आभासी आधार ctor पहले बुलाया जाएगा, लेकिन जब B से C वारिस आप किसी भी निर्दिष्ट नहीं करते हैं (उत्तरार्द्ध पहले से ही A, लेकिन लगभग विरासत में मिला है, इसलिए डिफ़ॉल्ट कहा जाता था)।

एक समाधान के रूप में आर्नी Mertz के जवाब में बताया गया आभासी विरासत को दूर करने के ... है। एक और (यदि आप वास्तव में आभासी विरासत चाहते हैं) C ctor से स्पष्ट रूप से A कॉल करने के लिए है:

C(int i, int j, int k} : A(i), B(i,j), _k(k){} 
0

आप वर्चुअल विरासत क्यों घोषित करते हैं? यदि आप कक्षा बी से वर्चुअल कीवर्ड हटाते हैं: वर्चुअल पब्लिक ए {... तो आपका कोड ठीक काम करेगा। आभासी ए घोषित करके, सी सीधे ए() को कॉल करेगा। यदि आप वर्चुअल को हटाते हैं तो सी ए() को कॉल नहीं करेगा।