2010-09-21 16 views
5

क्यों हमारे पास बेस क्लास में शुद्ध वर्चुअल असाइनमेंट ऑपरेटर है, तो हम उस ऑपरेटर को व्युत्पन्न कक्षा पर लागू करते हैं, यह बेस क्लास पर लिंकर त्रुटि देता है?सी ++: शुद्ध वर्चुअल असाइनमेंट ऑपरेटर

वर्तमान में मैं केवल यह कहा http://support.microsoft.com/kb/130486 पर निम्नलिखित विवरण दिया है कि व्यवहार सामान्य विरासत नियमों के बाद से डिजाइन के द्वारा होता है लागू नहीं होता।

यह मेरे लिए स्पष्ट नहीं है, यह डिज़ाइन द्वारा लिंकर त्रुटि क्यों उत्पन्न करता है? क्या कोई मुझे इस बारे में और स्पष्ट स्पष्टीकरण दे सकता है?

संपादित करें: मेरे सरलीकृत कोड जिनमें से त्रुटि हुई कहा:

class __declspec(dllexport) BaseClass { 
public: 
    int memberA; 
    virtual BaseClass& operator=(const BaseClass& rhs) = 0; 
}; 

class __declspec(dllexport) DerivedClass : public BaseClass { 
public: 
    int memberB; 
    DerivedClass():memberB(0) {} 
    virtual BaseClass& operator=(const BaseClass& rhs) { 
     this->memberA = rhs.memberA; 
     this->memberB = 1; 
     return *this; 
    } 
}; 

int main(void) 
{ 
    DerivedClass d1; 
    DerivedClass d2; 

    BaseClass* bd1 = &d1; 
    BaseClass* bd2 = &d2; 

    *bd1 = *bd2; 
} 

कोड के बिना शुद्ध आभासी ऑपरेटर__declspec(dllexport) और/या बिना कोई त्रुटि साथ संकलन = आधार वर्ग पर घोषणा करेंगे ।

*bd1 = *bd2; का काम करने के बाद __declspec(dllexport) बिना

, d1 :: memberB 1 है, लेकिन साथ __declspec(dllexport) d1 :: memberB __declspec(dllexport) साथ

अपरिवर्तित, और शुद्ध आभासी घोषणा के बिना छोड़ दिया है *bd1 = *bd2; का काम करने के बाद,, d1 :: memberB अपरिवर्तित

+2

पूर्ण लिंकर त्रुटि के साथ कुछ उदाहरण कोड पोस्ट करने में मददगार हो सकता है एमएसवीसी – Necrolis

+0

एफडब्ल्यूआईडब्ल्यू, स्कॉट मेयर्स के आइटम 33 और अधिक प्रभावी सी ++ _ ("गैर-लीफ क्लासेस सार बनाएं") को सौदा करने के तरीके को कवर करता है ऑपरेटर = विरासत पदानुक्रम में। –

+0

@necrolis: उदाहरण कोड – uray

उत्तर

7

मानक सेक्शन 12.8 से:

13 कक्षा X के लिए अंतर्निहित परिभाषित प्रति असाइनमेंट ऑपरेटर इसके उप-प्रोजेक्ट के सदस्यवार असाइनमेंट करता है। एक्स के प्रत्यक्ष आधार वर्ग, पहले आवंटित कर रहे हैं वे किस क्रम में घोषित किया गया में आधार-विनिर्देशक-सूची में उनकी घोषणा, और फिर एक्स के तत्काल गैर स्थिर डेटा सदस्यों आवंटित कर रहे हैं के क्रम में, कक्षा परिभाषा में।प्रत्येक subobject तरीके अपने प्रकार के लिए उपयुक्त में असाइन किया गया है:

- अगर subobject वर्ग प्रकार का है, वर्ग के लिए प्रति असाइनमेंट ऑपरेटर प्रयोग किया जाता है (जैसा कि स्पष्ट योग्यता से अगर; है कि, किसी भी संभव आभासी अनदेखी अधिक व्युत्पन्न कक्षाओं में कार्यों को ओवरराइड करना);

उपवर्ग परोक्ष परिभाषित प्रति असाइनमेंट ऑपरेटर उपयोग कर रहा है, और वहाँ आधार वर्ग के प्रति असाइनमेंट ऑपरेटर की कोई परिभाषा है, लेकिन यह, घोषित किया जाता है, ताकि आप एक लिंक त्रुटि बजाय का एक संकलन त्रुटि मिलती है।

+0

मुझे लगता है कि वह ऑपरेटर = के बारे में बात कर रहा है, न कि कॉपी कन्स्ट्रक्टर। प्रतिलिपि ctor के लिए - आभासी, और शुद्ध आभासी एक तत्काल संकलक त्रुटि होना चाहिए क्योंकि यह वास्तव में उनके लिए कोई समझ नहीं आता है। –

+2

उसका लिंक ऑपरेटर = के बारे में है और यही वह है जो मेरी पोस्ट के बारे में है। –

+0

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

7

ऑपरेटर = विरासत में नहीं छोड़ा गया है। आपका कोड सी ++ में व्यर्थ है, इसलिए कंपेलर इसके लिए इच्छित किसी भी त्रुटि को जारी करने के लिए स्वतंत्र हैं। http://support.microsoft.com/kb/130486

ऑपरेटर के बाद से = विरासत में मिला नहीं है, ऑपरेटर के किसी भी घोषणा = में आधार वर्ग अप्रयुक्त और अनावश्यक है:

KB लेख से आप की ओर इशारा किया। बेस क्लास में ऑपरेटर = घोषित न करें।

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

+0

वह उद्धरण कहां से है? –

+0

ओपी का केबी लेख। मैं उद्धरण –

+0

+1 को दूंगा, असाइनमेंट ऑपरेटर ओवरराइड हो गया है। किसी भी कन्स्ट्रक्टर (गैर-टेम्पलेट) को घोषित करने की तरह प्रभावशाली रूप से परिभाषित डिफ़ॉल्ट कन्स्ट्रक्टर को निष्क्रिय रूप से निष्क्रिय कर दें और कन्स्ट्रक्टर कॉपी करें, किसी भी 'ऑपरेटर =' (गैर-टेम्पलेट) को घोषित करने के लिए निहित परिभाषित असाइनमेंट ऑपरेटर को निष्क्रिय करें। – bjskishore123

2

उदाहरण कोड में:

class A 
{ 
public : 
    // To workaround LNK2001, comment the following line. 
    virtual const A& operator=(const A& f) = 0; 
}; 

class B : public A 
{ 
public : 
    const A& operator=(const A& g) {return g;} 
}; 

B aB1, aB2; 

int /*void*/ main(void) 
{ 
    aB2 = aB1; 
} 

लाइन aB2 = aB1const A& B::operator=(const A&) फोन नहीं करता है, लेकिन इसके बजाय कॉल स्वचालित रूप से आपूर्ति की B& operator=(const B&); जो बारी में वर्ग के आधार भाग असाइन करने के लिए असाइनमेंट ऑपरेटर का उपयोग करता है। लेकिन जब यह जोड़ने की बात आती है, तो यह पता चला कि इसे कभी लागू नहीं किया गया था।

+1

उद्धरण के लिए –

+0

@Matthieu: क्या यह * कॉपी असाइनमेंट * के रूप में योग्य है? और आखिरकार, 'स्ट्रक्चर एक्स {एक्स और ऑपरेटर = (int);};' मुझे एक एक्स को दूसरे को असाइन करने से नहीं रोकता है, अगर इसे * ऑपरेटर = 'के किसी भी अधिभार को डिफ़ॉल्ट रूप से अक्षम किया जाना चाहिए। - इसी प्रकार, कोई भी कन्स्ट्रक्टर कॉपी कन्स्ट्रक्टर को निष्क्रिय नहीं करता है, केवल वैध उपयोगकर्ता परिभाषित प्रति कन्स्ट्रक्टर। – UncleBens

+0

आप सही हैं, फिर भी 'बी और ऑपरेटर = (ए कॉन्स एंड)' का उपयोग करते समय इस संस्करण को डिफ़ॉल्ट के बजाय बुलाया जाता है (कम से कम वीसी ++ 10 के साथ) ... अब मैं उलझन में हूं और मेरे लिए बहुत देर हो चुकी है इसे देखने के लिए ... –