2010-08-16 19 views
10

क्या सामान्य (वर्चुअल) कन्स्ट्रक्टर कॉलिंग ऑर्डर को पास करने के लिए एक (व्यावहारिक) तरीका है?वर्चुअल बेस क्लास के ओवरलोडेड कन्स्ट्रक्टर को कॉल करना

उदाहरण:

class A 
{ 
    const int i; 

public: 
    A() 
     : i(0) 
    { cout << "calling A()" << endl; } 

    A(int p) 
     : i(p) 
    { cout << "calling A(int)" << endl; } 
}; 

class B 
    : public virtual A 
{ 
public: 
    B(int i) 
     : A(i) 
    { cout << "calling B(int)" << endl; } 
}; 

class C 
    : public B 
{ 
public: 
    C(int i) 
     : A(i), B(i) 
    { cout << "calling C(int)" << endl; } 
}; 

class D 
    : public C 
{ 
public: 
    D(int i) 
     : /*A(i), */ C(i) 
    { cout << "calling D(int)" << endl; } 
}; 


int main() 
{ 
    D d(42); 
    return 0; 
} 

आउटपुट:

बुला ए()
बी बुला (int)
बुला सी (int)
डी बुला (पूर्णांक)

(पूर्णांक)

बुला ए (int)
बी बुला
सी बुला (int)
बुला डी (int)


:

क्या मैं करना चाहता हूँ की तरह कुछ है

जैसा कि आप देखते हैं, वर्चुअल विरासत शामिल है, जो पहले के कन्स्ट्रक्टर को कॉल करने के लिए डी के निर्माता का नेतृत्व करती है, लेकिन चूंकि कोई पैरामीटर प्रदान नहीं किया जाता है, इसलिए यह ए() को कॉल करता है। कॉन्स int है जिसे प्रारंभिकरण की आवश्यकता है, इसलिए मुझे कोई समस्या है।

मैं सी के विरासत विवरण को छिपाने के लिए क्या करना चाहता हूं, यही कारण है कि मैं डी (और प्रत्येक व्युत्पन्न) कन्स्ट्रक्टर की प्रारंभिक सूची में ए (i) को कॉल करने से बचने का एक तरीका ढूंढ रहा हूं। [संपादित करें] इस विशिष्ट मामले में, मैं मान सकता हूं कि सी के केवल गैर-वर्चुअल एकल-विरासत बाल वर्ग हैं (जैसे डी एक है)। [/ संपादित करें]

[संपादित करें]

आभासी आधार वर्ग किसी भी गैर आभासी आधार वर्ग से पहले प्रारंभ कर रहे हैं प्रारंभ कर रहे हैं, तो केवल सबसे व्युत्पन्न वर्ग आभासी आधार वर्ग को प्रारंभ कर सकते हैं। - जेम्स McNellis

वास्तव में बात है कि, मैं नहीं सबसे व्युत्पन्न वर्ग आभासी आधार वर्ग निर्माता कॉल करना चाहते हैं

A 
/\ 
B0 B1 
\/
    C 
    | 
    D 

मुझे समझ में क्यों सी ए (अस्पष्टता) के ctor कॉल करने के लिए है जब आप: [/ संपादित करें]

निम्नलिखित स्थिति पर विचार करें ( ऊपर कोड उदाहरण में प्रतिनिधित्व नहीं) तत्काल सी, लेकिन डी को तुरंत चालू करते समय इसे क्यों कॉल करना है?

+1

मुझे विश्वास नहीं है कि आपके कोड उदाहरण आपके द्वारा प्रदान किए जाने वाले आउटपुट के साथ मेल खाते हैं। क्या आप सुनिश्चित हैं कि आप निर्देश "डी डी;" के साथ डी को instanciate ? –

+0

सूखी, मैं पैरामीटर भूल गया .... यह अब डी डी (42) है। धन्यवाद। – dyp

+0

ठीक है, यह अधिक उचित लगता है :-) क्या मैं पूछ सकता हूं कि आप "डरावने हीरे" वास्तुकला का उपयोग क्यों करना चाहते हैं? क्या आप अपने कोड को किसी अन्य तरीके से पुनर्गठित नहीं कर सकते? –

उत्तर

5

दुर्भाग्यवश, आपको सबसे व्युत्पन्न कक्षा से वर्चुअल बेस क्लास कन्स्ट्रक्टर को हमेशा कॉल करना होगा।

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

+0

> क्लास जो एक विटुअल बेस क्लास से सीधे प्राप्त होते हैं, मानक द्वारा, थियर विटुअल बेस क्लास कन्स्ट्रक्टर को कॉल नहीं करेंगे, इसलिए इसे स्पष्ट रूप से कॉल किया जाना चाहिए। कक्षा बी के लिए यह सही है, और फिर, कक्षा सी इसे कॉल कर सकता है। लेकिन चूंकि सी सबसे ज्यादा व्युत्पन्न कक्षा नहीं है, डी को इसे कॉल करना होगा। सी को कॉल करने का कोई तरीका है? डी सीधे सी से एक गैर-वर्चुअल विरासत के साथ लिया गया है। – dyp

+0

@DyP: मान लीजिए कि बाद में मैंने सी से प्राप्त कक्षा ई को जोड़ा है और फिर डी को दोनों सी और ई से प्राप्त किया जाता है (भले ही मैं सी वर्चुअल नहीं बनाता) तो कौन सी सी के लिए कन्स्ट्रक्टर कहता है? – diverscuba23

+0

उस के लिए सूखी, मैंने सवाल संपादित किया। मैं मान सकता हूं कि सी – dyp

-1

पैराशफ्ट सी ++ पर - इस मुद्दे को 0 -पर लाइट-लाइट करें।

+0

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

+0

@ डाइवर्सक्यूबा 23: मुझे यह समझने में कुछ खोज हुआ कि समस्या क्या थी। अब मुझे यह मिल गया है, लेकिन इस स्थिति को समझने वाली स्थिति को समझ में नहीं आता है। – Shamster

2

मुझे समझ में क्यों सी ए (अस्पष्टता) के ctor जब आप instanciate सी कॉल करने के लिए है, लेकिन क्यों डी संबंध है इसे कहते जब डी instanciating?

इसी कारण से सी को इसे कॉल करना है। यह अस्पष्टता का मुद्दा नहीं है, यह तथ्य है कि ए के रचनात्मक को केवल एक बार बुलाया जाना चाहिए (क्योंकि यह वर्चुअल बेस है)।

यदि आप उम्मीद कर रहे थे कि सी ए के कन्स्ट्रक्टर को शुरू करने में सक्षम हो तो क्या होगा यदि कक्षा डी को सी और दूसरी कक्षा का उत्तराधिकारी बनाया गया जो आखिरकार ए को विरासत में मिला?

+0

> [...] क्या होगा यदि कक्षा डी को दो सी के उत्तराधिकारी बनाया गया [...]? क्या मैं वस्तुतः सी से प्राप्त नहीं हुआ था? – dyp

+0

@ डीईपी: हाँ, दो सी के बारे में उचित बिंदु। मैंने इसे अपने उत्तर से संपादित कर लिया है। बिंदु अभी भी बेशक खड़ा है। – Troubadour

+0

@ डीईपी: निराशाजनक नहीं, अगर सी किसी ऑब्जेक्ट में स्वयं की कई प्रतियों का समर्थन कर सकता है, तो उसे वर्चुअल नहीं होना चाहिए। यह वास्तव में दुर्लभ माना जाता है कि आप कभी ऐसी स्थिति चाहते हैं, लेकिन भाषा के साथ करना संभव है। – diverscuba23

0

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

आभासी आधार वर्गों में वर्चुअल फ़ंक्शंस केवल एक अंतिम ओवरराइडर होना आवश्यक है, एक ओवरराइडर जो अन्य सभी ओवरड्रिड को ओवरराइड करता है। (गैर वर्चुअल बेस क्लास में वर्चुअल फ़ंक्शंस में संभवतः दो ओवर्रिडर्स नहीं हो सकते हैं, जैसे कि कोई अन्य को ओवरराइड नहीं करता है।)

लेकिन वर्चुअल बेस क्लास कन्स्ट्रक्टर हमेशा सबसे व्युत्पन्न वर्ग से और हमेशा के निहित रूप में नहीं बुलाए जाते हैं ctor-init-list में वर्चुअल बेस क्लास का उल्लेख करने के लिए परेशान, क्योंकि वर्चुअल बेस क्लास के रूप में उपयोग किए जाने वाले अधिकांश वर्ग "शुद्ध इंटरफेस" हैं, जिनमें कोई डेटा सदस्य नहीं है और कोई उपयोगकर्ता प्रारंभ नहीं है।

संबंधित मुद्दे