अगर मैं इसे ओवरराइड कर रहा हूं तो क्या मैं बेस क्लास के वर्चुअल फंक्शन को कॉल कर सकता हूं?


340

कहो कि मेरे पास कक्षाएं हैं Fooऔर Barइस तरह सेट करें:

class Foo
{
public:
    int x;

    virtual void printStuff()
    {
        std::cout << x << std::endl;
    }
};

class Bar : public Foo
{
public:
    int y;

    void printStuff()
    {
        // I would like to call Foo.printStuff() here...
        std::cout << y << std::endl;
    }
};

जैसा कि कोड में एनोटेट किया गया है, मैं बेस क्लास के फ़ंक्शन को कॉल करने में सक्षम होना चाहता हूं जो मैं ओवरराइड कर रहा हूं। जावा में super.funcname()वाक्य रचना है। क्या यह C ++ में संभव है?



1
गोगलर्स के लिए: ध्यान दें कि आपके पास ऐसे मुद्दे हो सकते हैं जैसे मैंने इसे एक वर्ग के सदस्य चर के रूप में संग्रहीत किया है जो कि सूचक नहीं है। मेरा जवाब यहां देखें: stackoverflow.com/questions/4798966/… मैंने ठीक करने के लिए नया / डिलीट किया।
एंड्रयू

जवाबों:


449

C ++ सिंटैक्स इस प्रकार है:

class Bar : public Foo {
  // ...

  void printStuff() {
    Foo::printStuff(); // calls base class' function
  }
};

11
क्या ऐसा करने के साथ कोई संभावित समस्या है? क्या यह बुरा अभ्यास है?
Robben_Ford_Fan_boy

36
@ डेविड: नहीं, ऐसा करना पूरी तरह से सामान्य है, हालांकि यह आपके वास्तविक वर्ग पर निर्भर हो सकता है यदि यह वास्तव में उपयोगी है। केवल बेस क्लास विधि को कॉल करें यदि आप कुछ करना चाहते हैं;)।
sth

20
जब आपके ग्राहक इसे करने के लिए आवश्यक हो जाते हैं तो यह एक कोड गंध है! (कहा जाता है call super requirement, इसे यहाँ देखें: en.wikipedia.org/wiki/Call_super )
v.oddou

8
@ v.oddou: जब यह उपयोगी है तो सुपर क्लास को कॉल करने में कुछ भी गलत नहीं है। आपके द्वारा जोड़ा गया वह पृष्ठ वंशानुक्रम से जुड़ी कुछ विशिष्ट संभावित समस्या के बारे में है। यह स्वयं भी कहता है कि सुपर क्लास को सामान्य रूप से कॉल करने में कुछ भी गलत नहीं है: "ध्यान दें कि यह माता-पिता को कॉल करने की आवश्यकता है जो कि विरोधी पैटर्न है। वास्तविक कोड में कई उदाहरण हैं जहां उपवर्ग में विधि अभी भी हो सकती है। सुपरक्लास की कार्यक्षमता चाहते हैं, आमतौर पर जहां यह केवल मूल कार्यक्षमता को बढ़ाता है। "
sth

26
यह अधिकांश के लिए स्पष्ट हो सकता है, लेकिन पूर्णता के लिए, यह याद रखें कि कभी भी निर्माणकर्ताओं और विध्वंसक में ऐसा न करें।
टाइगरकोडिंग

123

हाँ,

class Bar : public Foo
{
    ...

    void printStuff()
    {
        Foo::printStuff();
    }
};

यह superजावा की तरह ही है , सिवाय इसके कि जब आपके पास एक से अधिक विरासत हों, तो विभिन्न आधारों से कार्यान्वयन को कॉल करने की अनुमति मिलती है।

class Foo {
public:
    virtual void foo() {
        ...
    }
};

class Baz {
public:
    virtual void foo() {
        ...
    }
};

class Bar : public Foo, public Baz {
public:
    virtual void foo() {
        // Choose one, or even call both if you need to.
        Foo::foo();
        Baz::foo();
    }
};

7
यह चयनित से बेहतर उत्तर है। धन्यवाद।
मैड फिजिसिस्ट

एकाधिक विरासत? ऊँ यक्ष!
लैमिनो

69

कभी-कभी आपको बेस क्लास के कार्यान्वयन को कॉल करने की आवश्यकता होती है, जब आप व्युत्पन्न फ़ंक्शन में नहीं होते हैं ... यह अभी भी काम करता है:

struct Base
{
    virtual int Foo()
    {
        return -1;
    }
};

struct Derived : public Base
{
    virtual int Foo()
    {
        return -2;
    }
};

int main(int argc, char* argv[])
{
    Base *x = new Derived;

    ASSERT(-2 == x->Foo());

    //syntax is trippy but it works
    ASSERT(-1 == x->Base::Foo());

    return 0;
}

2
ध्यान दें कि आपको काम करने के लिए दोनों xप्रकार के होने Base*और Base::Fooवाक्यविन्यास का उपयोग करने की आवश्यकता है
TTimo

27

यदि आप अपनी कक्षा में बहुत सारे कार्यों के लिए ऐसा करते हैं:

class Foo {
public:
  virtual void f1() {
    // ...
  }
  virtual void f2() {
    // ...
  }
  //...
};

class Bar : public Foo {
private:
  typedef Foo super;
public:
  void f1() {
    super::f1();
  }
};

यदि आप फू का नाम बदलना चाहते हैं, तो यह थोड़ा लेखन को बचा सकता है।


1
यह करने के लिए मजेदार तरीका है, लेकिन कई विरासत के साथ काम नहीं करेगा।
मैड फिजिसिस्ट

5
और अगर आपके पास 1 से अधिक बेस क्लास है तो क्या होगा? वैसे भी, यह कुछ और भाषा की तरह दिखने के लिए C ++ को मोड़ने की कोशिश करने के लिए मूर्खतापूर्ण और अक्सर व्यर्थ है। बस आधार का नाम याद रखें और उसके द्वारा कॉल करें।
अंडरस्कोर_ड

6

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

कोड यहाँ जाता है

#include <iostream>
using namespace std;

class Foo
{
public:
    int x;

    virtual void printStuff()
    {
         cout<<"Base Foo printStuff called"<<endl;
    }
};

class Bar : public Foo
{
public:
    int y;

    void printStuff()
    {
        cout<<"derived Bar printStuff called"<<endl;
        Foo::printStuff();/////also called the base class method
    }
};

int main()
{
    Bar *b=new Bar;
    b->printStuff();
}

फिर से आप रनटाइम पर निर्धारित कर सकते हैं कि उस वर्ग (व्युत्पन्न या आधार) के ऑब्जेक्ट का उपयोग करने के लिए कौन सा फ़ंक्शन है। लेकिन इसके लिए बेस क्लास में आपके फ़ंक्शन को वर्चुअल के रूप में चिह्नित किया जाना चाहिए।

नीचे कोड

#include <iostream>
using namespace std;

class Foo
{
public:
    int x;

    virtual void printStuff()
    {
         cout<<"Base Foo printStuff called"<<endl;
    }
};

class Bar : public Foo
{
public:
    int y;

    void printStuff()
    {
        cout<<"derived Bar printStuff called"<<endl;
    }
};

int main()
{

    Foo *foo=new Foo;
    foo->printStuff();/////this call the base function
    foo=new Bar;
    foo->printStuff();
}

0

इसे देखो...

#include <stdio.h>

class Base {
public:
   virtual void gogo(int a) { printf(" Base :: gogo (int) \n"); };    
   virtual void gogo1(int a) { printf(" Base :: gogo1 (int) \n"); };
   void gogo2(int a) { printf(" Base :: gogo2 (int) \n"); };    
   void gogo3(int a) { printf(" Base :: gogo3 (int) \n"); };
};

class Derived : protected Base {
public:
   virtual void gogo(int a) { printf(" Derived :: gogo (int) \n"); };
   void gogo1(int a) { printf(" Derived :: gogo1 (int) \n"); };
   virtual void gogo2(int a) { printf(" Derived :: gogo2 (int) \n"); };
   void gogo3(int a) { printf(" Derived :: gogo3 (int) \n"); };       
};

int main() {
   std::cout << "Derived" << std::endl;
   auto obj = new Derived ;
   obj->gogo(7);
   obj->gogo1(7);
   obj->gogo2(7);
   obj->gogo3(7);
   std::cout << "Base" << std::endl;
   auto base = (Base*)obj;
   base->gogo(7);
   base->gogo1(7);
   base->gogo2(7);
   base->gogo3(7);

   std::string s;
   std::cout << "press any key to exit" << std::endl;
   std::cin >> s;
   return 0;
}

उत्पादन

Derived
 Derived :: gogo (int)
 Derived :: gogo1 (int)
 Derived :: gogo2 (int)
 Derived :: gogo3 (int)
Base
 Derived :: gogo (int)
 Derived :: gogo1 (int)
 Base :: gogo2 (int)
 Base :: gogo3 (int)
press any key to exit

आधार का उपयोग करने का सबसे अच्छा तरीका है :: फ़ंक्शन @sth के रूप में


जैसा कि इस प्रश्न में बताया गया है , यह protectedवंशानुक्रम के कारण काम नहीं करना चाहिए । बेस क्लास पॉइंटर डालने के लिए आपको पब्लिक इनहेरिटेंस का इस्तेमाल करना होगा।
डार्कप्रोडक्ट

दिलचस्प। इस उत्तर को पढ़ने के बाद, मैंने संरक्षित विरासत के साथ सोचा कि यह तथ्य कि व्युत्पन्न बेस से लिया गया है, केवल कक्षा में ही दिखाई देगा और बाहर भी दिखाई नहीं देगा।
डार्कप्रोडक्ट

0

हां आप इसे कॉल कर सकते हैं। चाइल्ड क्लास में पेरेंट क्लास फ़ंक्शन को कॉल करने के लिए C ++ सिंटैक्स है

class child: public parent {
  // ...

  void methodName() {
    parent::methodName(); // calls Parent class' function
  }
};

फ़ंक्शन ओवरराइडिंग के बारे में और पढ़ें ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.