C ++ वर्चुअल फ़ंक्शंस को सुरक्षित रूप से ओवरराइड करें


100

मेरे पास वर्चुअल फ़ंक्शन के साथ एक बेस क्लास है और मैं उस फ़ंक्शन को एक व्युत्पन्न वर्ग में ओवरराइड करना चाहता हूं। क्या संकलक जांच करने का कोई तरीका है यदि मैं व्युत्पन्न वर्ग में घोषित फ़ंक्शन वास्तव में बेस क्लास में एक फ़ंक्शन को ओवरराइड करता है? मैं कुछ मैक्रो या कुछ जोड़ना चाहता हूं जो यह सुनिश्चित करता है कि मैंने पुराने को ओवरराइड करने के बजाय गलती से एक नया फ़ंक्शन घोषित नहीं किया।

इस उदाहरण को लें:

class parent {
public:
  virtual void handle_event(int something) const {
    // boring default code
  }
};

class child : public parent {
public:
  virtual void handle_event(int something) {
    // new exciting code
  }
};

int main() {
  parent *p = new child();
  p->handle_event(1);
}

यहां parent::handle_event()इसके बजाय कहा जाता है child::handle_event(), क्योंकि बच्चे की विधि constघोषणा को याद करती है और इसलिए एक नई विधि घोषित करती है। यह फ़ंक्शन नाम या पैरामीटर प्रकारों में कुछ मामूली अंतर का एक टाइपो भी हो सकता है। यह आसानी से भी हो सकता है अगर बेस क्लास का इंटरफ़ेस बदल जाए और कहीं न कहीं कुछ व्युत्पन्न वर्ग इस बदलाव को प्रतिबिंबित करने के लिए अपडेट नहीं किया गया।

क्या इस समस्या से बचने का कोई तरीका है, क्या मैं किसी तरह कंपाइलर या किसी अन्य उपकरण को यह बता सकता हूँ कि यह मेरे लिए है? किसी भी सहायक संकलक झंडे (अधिमानतः जी ++ के लिए)? आप इन समस्याओं से कैसे बचेंगे?


2
महान सवाल, मैं यह जानने की कोशिश कर रहा हूं कि मेरा बच्चा क्लास फंक्शन क्यों नहीं करता है, अब एक घंटे के बाद फोन किया जाता है!
आकाश मानकर

जवाबों:


89

G ++ 4.7 के बाद से यह नए C ++ 11 overrideकीवर्ड को समझता है :

class child : public parent {
    public:
      // force handle_event to override a existing function in parent
      // error out if the function with the correct signature does not exist
      void handle_event(int something) override;
};

@hirschhornsalz: मैंने पाया कि जब आप handle_event फ़ंक्शन को लागू करते हैं और आप फ़ंक्शन कार्यान्वयन के अंत में ओवरराइड को जोड़ते हैं, तो जी ++ एक त्रुटि देता है; यदि आप ओवरराइड कीवर्ड के बाद वर्ग घोषणा में इनलाइन फ़ंक्शन कार्यान्वयन प्रदान करते हैं, तो सब कुछ ठीक है। क्यों?
h9uest

3
@ h9uest overrideका उपयोग परिभाषा में किया जाना चाहिए। इनलाइन कार्यान्वयन परिभाषा और कार्यान्वयन दोनों है, इसलिए ठीक है।
गुंथर पाईज

@hirschhornsalz हाँ, मुझे वही त्रुटि मिल गई g ++ द्वारा। एक साइड नोट, हालांकि: आप और जी ++ त्रुटि वाले दोनों ने "क्लास डेफिनिशन" शब्द का उपयोग किया है - क्या हमें "घोषणा" ({घोषणा, परिभाषा} जोड़ी) का उपयोग नहीं करना चाहिए? आपने "परिभाषा और कार्यान्वयन" कहकर इस विशेष संदर्भ में अपने आप को स्पष्ट कर दिया, लेकिन मुझे आश्चर्य है कि c ++ समुदाय अचानक वर्गों के संदर्भ में बदलाव का फैसला क्यों करता है?
h9uest

20

C # के overrideकीवर्ड जैसा कुछ C ++ का हिस्सा नहीं है।

Gcc में, -Woverloaded-virtualबेस क्लास वर्चुअल फंक्शन को एक ही नाम के फंक्शन के साथ छुपाने के खिलाफ चेतावनी देता है , लेकिन पर्याप्त रूप से अलग सिग्नेचर जो इसे बाधित नहीं करता है। हालाँकि, यह फ़ंक्शन नाम की गलत वर्तनी के कारण किसी फ़ंक्शन को ओवरराइड करने में विफल होने से आपकी रक्षा नहीं करेगा।


2
यदि आप विजुअल C ++
स्टीव रोवे

4
विजुअल C ++ का उपयोग करने से C ++ में कोई overrideकीवर्ड नहीं बनता है; इसका अर्थ यह हो सकता है कि आप कुछ ऐसा उपयोग कर रहे हैं जो कुछ अमान्य C ++ स्रोत कोड को संकलित कर सकता है। ;)
सीबी बेली 16

3
तथ्य यह है कि ओवरराइड अमान्य है C ++ का मतलब है कि मानक गलत है, और विजुअल C ++
जॉन

2
@ जॉन: ठीक है, अब मैं देखता हूँ कि तुम क्या कर रहे थे। व्यक्तिगत रूप से मैं C # स्टाइल overrideकार्यक्षमता ले या छोड़ सकता था ; मुझे शायद ही कभी असफल ओवरराइड की समस्या हुई हो और उनका निदान करना और ठीक करना अपेक्षाकृत आसान रहा हो। मुझे लगता है कि मैं इससे सहमत नहीं हूं कि VC ++ उपयोगकर्ता इसका उपयोग करें। मैं पसंद करूंगा कि C ++ सभी प्लेटफार्मों पर C ++ की तरह दिखे, भले ही एक विशेष परियोजना को पोर्टेबल होने की आवश्यकता न हो। यह ध्यान देने योग्य है कि C ++ 0x में होगा [[base_check]], [[override]]और [[hiding]]यदि आप चाहें तो चेकिंग को ओवरराइड करने का विकल्प चुन सकते हैं।
सीबी बेली

5
मजेदार रूप से पर्याप्त है, VC ++ का उपयोगoverride करने वाले टिप्पणी के कुछ साल बाद ऐसा कोई कीवर्ड नहीं बनता जिससे ऐसा लगे । ठीक है, एक उचित कीवर्ड नहीं, लेकिन C ++ 11 में एक विशेष पहचानकर्ता। Microsoft ने इसके बारे में एक विशेष मामला बनाने के लिए और विशेषताओं के लिए सामान्य प्रारूप का पालन करने के लिए पर्याप्त जोर दिया और overrideइसे मानक में बनाया :)
डेविड रॉड्रिग्ज - dribeas

18

जहाँ तक मुझे पता है, क्या आप इसे अमूर्त नहीं बना सकते?

class parent {
public:
  virtual void handle_event(int something) const = 0 {
    // boring default code
  }
};

मैंने सोचा कि मैं www.parashift.com पर पढ़ता हूं कि आप वास्तव में एक अमूर्त पद्धति को लागू कर सकते हैं। जो मुझे व्यक्तिगत रूप से समझ में आता है, केवल एक चीज जो इसे लागू करने के लिए उपवर्गों को मजबूर करती है, किसी ने भी इस बारे में कुछ नहीं कहा कि इसे स्वयं लागू करने की अनुमति नहीं है।


केवल अब मैंने महसूस किया है कि यह काम सिर्फ विध्वंसक से अधिक है! शानदार खोज।
स्ट्रैजर

1
इसमें कुछ संभावित कमियां हैं: 1) दूसरी चीज जो अमूर्त के रूप में एक या एक से अधिक तरीकों को चिह्नित करती है, वह आधार वर्ग को गैर-तात्कालिक बना देती है, जो वर्ग के इच्छित उपयोग का हिस्सा नहीं होने पर एक समस्या हो सकती है। 2) आधार वर्ग पहली जगह में संशोधित करने के लिए आपका नहीं हो सकता है।
माइकल बूर

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

यह आधार पद्धति (कहते हैं BaseClass::method()) को व्युत्पन्न कार्यान्वयन (कहते हैं DerivedClass::method()) में कहा जाता है , जैसे कि डिफ़ॉल्ट मान के लिए।
नारकोलेसिको

11

MSVC में, आप CLR overrideकीवर्ड का उपयोग कर सकते हैं, भले ही आप CLR के लिए संकलन न कर रहे हों।

जी ++ में, सभी मामलों में इसे लागू करने का कोई सीधा तरीका नहीं है; अन्य लोगों ने इस पर अच्छे उत्तर दिए हैं कि कैसे हस्ताक्षर अंतरों को पकड़ना है -Woverloaded-virtual। भविष्य के संस्करण में, कोई व्यक्ति __attribute__ ((override))सी ++ 0x सिंटैक्स का उपयोग करके सिंटैक्स की तरह या समकक्ष जोड़ सकता है ।


9

MSVC ++ में आप कीवर्ड का उपयोग कर सकते हैंoverride

class child : public parent {
public:
  virtual void handle_event(int something) <b>override</b> {
    // new exciting code
  }
};

override MSVC ++ में देशी और सीएलआर कोड दोनों के लिए काम करता है।


5

फ़ंक्शन को अमूर्त बनाएं, ताकि व्युत्पन्न वर्गों के पास इसे ओवरराइड करने के अलावा कोई अन्य विकल्प न हो।

@ आपका कोड अमान्य है।

class parent {
public:
  virtual void handle_event(int something) const = 0 {
    // boring default code
  }
};

सार कार्यों में इनलाइन परिभाषित निकाय नहीं हो सकते। इसे बनने के लिए संशोधित करना होगा

class parent {
public:
  virtual void handle_event(int something) const = 0;
};

void parent::handle_event( int something ) { /* do w/e you want here. */ }

3

मैं आपके तर्क में थोड़ा बदलाव करने का सुझाव दूंगा। यह काम करने या न करने पर निर्भर करता है कि आपको क्या हासिल करना है।

handle_event () अभी भी "उबाऊ डिफ़ॉल्ट कोड" कर सकते हैं, लेकिन आभासी होने के बजाय, उस बिंदु पर जहां आप "नया रोमांचक कोड" करना चाहते हैं, बेस क्लास को एक सार विधि (यानी-होना चाहिए-ओवरराइड) विधि है जो आपके वंशज वर्ग द्वारा आपूर्ति की जाएगी।

संपादित करें: और यदि आप बाद में निर्णय लेते हैं कि आपके कुछ वंशजों को "नया रोमांचक कोड" प्रदान करने की आवश्यकता नहीं है, तो आप अमूर्त को आभासी में बदल सकते हैं और उस "सम्मिलित" कार्यक्षमता के खाली आधार वर्ग कार्यान्वयन की आपूर्ति कर सकते हैं।


2

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

उदाहरण के लिए, यह Microsoft Visual C ++ में C4263 चेतावनी दे रहा है।


1

सी ++ 11 override कीवर्ड जब व्युत्पन्न वर्ग के अंदर फ़ंक्शन घोषणा के साथ उपयोग किया जाता है, तो यह संकलक को यह जांचने के लिए मजबूर करता है कि घोषित फ़ंक्शन वास्तव में कुछ बेस क्लास फ़ंक्शन को ओवरराइड कर रहा है। अन्यथा, संकलक एक त्रुटि फेंक देगा।

इसलिए आप overrideगतिशील बहुरूपता (फ़ंक्शन ओवरराइडिंग) सुनिश्चित करने के लिए स्पेसियर का उपयोग कर सकते हैं ।

class derived: public base{
public:
  virtual void func_name(int var_name) override {
    // statement
  }
};
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.