//header.h
#include<iostream>
using namespace std;
struct Base {
    virtual void vf();
};
struct Derived :Base {
    virtual void vf();
};
inline void Base::vf() {
    cout << "Base::vf()" << endl;
}
inline void Derived::vf() {
    cout << "Derived::vf()" << endl;
}

//source.cpp
#include"header.h"
int main() {
    Base *pb = new Derived;
    pb->vf();
}

//source2.cpp
#include"header.h"

यह एमएसवीसी और जी ++ में संकलित और काम करता है।

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

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

क्या मुझे कुछ गलत लगता है?

c++
2
sakugawa 1 नवम्बर 2020, 20:11

2 जवाब

सबसे बढ़िया उत्तर

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

यदि आप अपने कार्यों को चिह्नित नहीं करना चाहते हैं inline (और आप उन्हें कक्षा परिभाषा के अंदर परिभाषित नहीं करना चाहते हैं, जो उन्हें अंतर्निहित रूप से इनलाइन बनाता है), तो आपको प्रत्येक फ़ंक्शन परिभाषा को बिल्कुल एक स्रोत फ़ाइल में रखना होगा। . एक उपयोगी पहला कदम एक एकल स्रोत फ़ाइल में एक वर्ग के सभी गैर-इनलाइन सदस्य कार्यों को परिभाषित करना है। तो आपका source2.cpp ऐसा दिखाई दे सकता है (हां, यह दो वर्गों से सदस्य कार्य करता है):

#include "header.h"
#include <iostream>

void Base::vf() {
    std::cout << "Base::vf()\n";
}

void Derived::vf() {
    std::cout << "Derived::vf()\n";
}

और आप उन परिभाषाओं को header.h से हटा देंगे। तो अब header.h में केवल वर्ग परिभाषा है; source2.cpp में सदस्य कार्यों की परिभाषा है; और source.cpp में main फ़ंक्शन है।

2
Pete Becker 1 नवम्बर 2020, 22:35

एक परिभाषा नियम अनिवार्य है। यह सी ++ द्वारा आवश्यक है। किसी दिए गए ऑब्जेक्ट या फ़ंक्शन को ठीक एक बार परिभाषित किया जाना चाहिए। inline कीवर्ड (आपके मामले में) को हटाने से इस नियम का उल्लंघन होता है, जिससे परिणामी प्रोग्राम खराब हो जाता है।

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

यह सच है कि ओडीआर उल्लंघन के लिए निदान की आवश्यकता नहीं होती है, लेकिन परिणामी कोड अभी भी टूटा हुआ है। समस्या के प्रति सचेत करने के लिए कृपया अपने कंपाइलर को धन्यवाद नोट लिखें।

2
Sam Varshavchik 1 नवम्बर 2020, 22:49