व्युत्पन्न वर्ग फ़ंक्शन से एक मूल वर्ग फ़ंक्शन कैसे कॉल करें?


602

मैं C ++ का उपयोग करके एक व्युत्पन्न वर्ग से मूल फ़ंक्शन को कैसे कॉल करूं? उदाहरण के लिए, मेरे पास एक वर्ग है parent, और एक वर्ग है जिसे बुलाया जाता हैchild अभिभावक कहते हैं। प्रत्येक कक्षा के भीतर एक printफ़ंक्शन होता है। बच्चे के प्रिंट फ़ंक्शन की परिभाषा में मैं माता-पिता के प्रिंट फ़ंक्शन को कॉल करना चाहूंगा। मैं ऐसा कैसे कर पाऊंगा?


उपरोक्त सभी समाधान मान रहे हैं कि आपका प्रिंट फ़ंक्शन एक स्थिर विधि है। क्या यह मामला है? यदि विधि स्थिर नहीं है, तो उपरोक्त समाधान प्रासंगिक नहीं हैं।
हफीज

14
hhafez, आपको गलत किया गया है आधार :: फ़ंक्शन () सिंटैक्स स्थिर विधि कॉल सिंटैक्स की तरह दिखता है, लेकिन यह इस संदर्भ में उदाहरण के तरीकों के लिए काम करता है।
18

2
जब से यह मंच विशिष्ट है मैं MSVC __super का उपयोग नहीं करेगा। यद्यपि आपका कोड किसी अन्य प्लेटफ़ॉर्म पर नहीं चल सकता है, मैं अन्य सुझावों का उपयोग करूंगा क्योंकि वे इसे भाषा के अनुसार करते हैं।
टीज़र


एंटीपैर्टन जहां व्युत्पन्न वर्गों को हमेशा माता-पिता के कार्यों को कॉल करने की आवश्यकता होती है, कॉल सुपर है
रुफस

जवाबों:


774

मैं स्पष्ट कहने का जोखिम उठाऊंगा: आप फ़ंक्शन को कॉल करते हैं, यदि यह आधार वर्ग में परिभाषित है, तो यह स्वचालित रूप से व्युत्पन्न वर्ग में उपलब्ध है (जब तक कि यह नहीं है private )।

यदि व्युत्पन्न वर्ग में एक ही हस्ताक्षर के साथ एक फ़ंक्शन है, तो आप इसे आधार वर्ग के नाम के साथ दो कॉलोन जोड़कर इसे मना कर सकते हैं base_class::foo(...)। आपको ध्यान देना चाहिए कि जावा और C # के विपरीत, C ++ में "बेस क्लास" के लिए एक कीवर्ड नहीं है ( superया base) चूंकि C ++ मल्टीपल इनहेरिटेंस का समर्थन करता है जिससे अस्पष्टता हो सकती है।

class left {
public:
    void foo();
};

class right {
public:
    void foo();
};

class bottom : public left, public right {
public:
    void foo()
    {
        //base::foo();// ambiguous
        left::foo();
        right::foo();

        // and when foo() is not called for 'this':
        bottom b;
        b.left::foo();  // calls b.foo() from 'left'
        b.right::foo();  // call b.foo() from 'right'
    }
};

संयोग से, आप सीधे एक ही कक्षा से दो बार प्राप्त नहीं कर सकते क्योंकि आधार कक्षाओं में से एक को दूसरे पर संदर्भित करने का कोई तरीका नहीं होगा।

class bottom : public left, public left { // Illegal
};

30
आप एक ही वर्ग से दो बार विरासत में क्यों लेना चाहेंगे?
पॉल ब्रूसकिनस्की

65
@bluesm: क्लासिक OOP में इसका कोई अर्थ नहीं है, लेकिन जेनेरिक प्रोग्रामिंग में template<class A, class B> class C: public A, public B {};दो प्रकार के कारण आ सकते हैं जो आपके कोड के उपयोग के आधार पर समान हो सकते हैं (जो A और B को समान बनाता है), दो या तीन हो सकते हैं अमूर्त परत रास्ता किसी से पता नहीं तुमने क्या किया।
एमिलियो गरवागलिया

8
मुझे लगता है कि यह जोड़ना उपयोगी है, कि यह पैरेंट क्लास पद्धति को कॉल करेगा भले ही इसे सीधे पैरेंट क्लास में लागू न किया गया हो, लेकिन इनहेरिटेंस चेन में पैरेंट क्लास में से एक में लागू किया जाता है
मैक्सिम लावरोव

4
जब मैंने इसे एक cpp फ़ाइल में डालने की कोशिश की, तो एक सिडनोट पर, इसने मुझे पागल कर दिया। मैंने 'नेमस्पेस स्टड' का उपयोग किया था। 'वाम' को उस नामस्थान में कहीं परिभाषित किया गया है। उदाहरण संकलन नहीं होगा - मुझे पागल कर दिया :)। फिर मैंने 'लेफ्ट' को 'लेफ्ट' में बदल दिया। वैसे शानदार उदाहरण।
मथाई

72
@ मथाई और इसीलिए आप उपयोग करने वाले नहीं हैं using namespace std
JAB

193

नामित अभिभावक वर्ग Parentऔर नामित बाल वर्ग को देखते हुए Child, आप कुछ इस तरह कर सकते हैं:

class Parent {
public:
    virtual void print(int x);
}

class Child : public Parent {
    void print(int x) override;
}

void Parent::print(int x) {
    // some default behavior
}

void Child::print(int x) {
    // use Parent's print method; implicitly passes 'this' to Parent::print
    Parent::print(x);
}

ध्यान दें कि Parentकक्षा का वास्तविक नाम है न कि कोई कीवर्ड।


बेशक, यह केवल तभी उपयोगी होगा जब आधार कॉल को अन्य तर्क के साथ जोड़ दिया गया था, अन्यथा फ़ंक्शन को ओवरराइड करने का कोई मतलब नहीं होगा, इसलिए शायद यह थोड़ा - बहुत -से-बिंदु है;)
अंडरस्कोर_ड

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

@ जिहानी दिलचस्प लगता है, लेकिन क्षमा करें, मैं इसे अभी तक नहीं समझ रही हूं। है foo()यहाँ के अनुरूप print()या एक अलग समारोह? और क्या आप privateआधार से विरासत में प्राप्त विवरणों को छिपाने के लिए विरासत का उपयोग करके , और publicउन चीजों के लिए छायांकन कार्य प्रदान करते हैं जिन्हें आप उजागर करना चाहते हैं?
अंडरस्कोर_ड

@underscore_d हाँ, के foo()अनुरूप था print()। मुझे print()लगता है कि मैं इस संदर्भ में इसे और अधिक समझ में आता हूं। मान लीजिए कि किसी ने एक वर्ग बनाया, जिसने किसी विशेष डेटाटाइप पर कुछ संचालन का संचालन किया, कुछ एक्सेसरों को उजागर किया, और एक print(obj&)विधि थी। मुझे एक नए वर्ग की आवश्यकता है जो काम करता है array-of-objलेकिन बाकी सब समान है। रचना में बहुत सारे डुप्लिकेट कोड हैं। वंशानुक्रम print(array-of-obj&) लूप कॉलिंग में कम से कम है, print(obj&)लेकिन ग्राहकों को कॉल करने के लिए नहीं चाहते print(obj&)क्योंकि उनके लिए ऐसा करने का कोई मतलब नहीं है
iheanyi

@underscore_d यह इस धारणा पर आधारित है कि मैं मूल अभिभावक वर्ग के सामान्य भागों को वापस नहीं ला सकता या ऐसा करना अविश्वसनीय रूप से महंगा है। निजी विरासत काम कर सकती है, लेकिन फिर आप उन सार्वजनिक एक्सेसरों को खो देते हैं, जिन पर आप भरोसा कर रहे थे - और इस प्रकार, कोड को डुप्लिकेट करने की आवश्यकता होगी।
इहनी

32

यदि आपका आधार वर्ग कहा जाता है Base, और आपका कार्य कहा जाता है, FooBar()तो आप इसे सीधे उपयोग करके कॉल कर सकते हैंBase::FooBar()

void Base::FooBar()
{
   printf("in Base\n");
}

void ChildOfBase::FooBar()
{
  Base::FooBar();
}

28

MSVC में उसके लिए एक Microsoft विशिष्ट कीवर्ड है: __super


MSDN: आपको स्पष्ट रूप से यह बताने की अनुमति देता है कि आप एक फ़ंक्शन के लिए बेस-क्लास कार्यान्वयन को बुला रहे हैं जिसे आप ओवरराइड कर रहे हैं।

// deriv_super.cpp
// compile with: /c
struct B1 {
   void mf(int) {}
};

struct B2 {
   void mf(short) {}

   void mf(char) {}
};

struct D : B1, B2 {
   void mf(short) {
      __super::mf(1);   // Calls B1::mf(int)
      __super::mf('s');   // Calls B2::mf(char)
   }
};


5
एह, मैं typdefमाता पिता की तरह कुछ के रूप में आईएनजी पसंद करेंगे super
थॉमस ईडिंग

26
मैं इसके उपयोग को सही ठहराने की कोशिश नहीं करूंगा __super; मैंने इसे एक वैकल्पिक सुझाव के रूप में यहां उल्लेख किया है। डेवलपर्स को अपने संकलक को जानना चाहिए और इसकी क्षमताओं के पेशेवरों और विपक्षों को समझना चाहिए।
एंड्री

13
मैं इसके इस्तेमाल से किसी को भी हतोत्साहित करूंगा, क्योंकि यह कोड की पोर्टेबिलिटी को गंभीर रूप से बाधित करता है।
एरब्यूरथ का कहना है कि मोनिका

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

7
"डेवलपर्स को अपने संकलक को जानना चाहिए" इस तर्क को, और गैर मानक विशेषताओं को शामिल करने के लिए, IE6 का नेतृत्व किया ...
e2-e4

5

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

#include<iostream>
using namespace std;

class Parent
{
  protected:
    virtual void fun(int i)
    {
      cout<<"Parent::fun functionality write here"<<endl;
    }
    void fun1(int i)
    {
      cout<<"Parent::fun1 functionality write here"<<endl;
    }
    void fun2()
    {

      cout<<"Parent::fun3 functionality write here"<<endl;
    }

};

class Child:public Parent
{
  public:
    virtual void fun(int i)
    {
      cout<<"Child::fun partial functionality write here"<<endl;
      Parent::fun(++i);
      Parent::fun2();
    }
    void fun1(int i)
    {
      cout<<"Child::fun1 partial functionality write here"<<endl;
      Parent::fun1(++i);
    }

};
int main()
{
   Child d1;
   d1.fun(1);
   d1.fun1(2);
   return 0;
}

आउटपुट:

$ g++ base_function_call_from_derived.cpp
$ ./a.out 
Child::fun partial functionality write here
Parent::fun functionality write here
Parent::fun3 functionality write here
Child::fun1 partial functionality write here
Parent::fun1 functionality write here

1
कुछ उदाहरणों को साथ लाने के लिए धन्यवाद virtual!
एम। इयान

5

मूल विधि संकल्प ऑपरेटर के साथ मूल विधि को कॉल करें।

जनक :: विधि ()

class Primate {
public:
    void whatAmI(){
        cout << "I am of Primate order";
    }
};

class Human : public Primate{
public:
    void whatAmI(){
        cout << "I am of Human species";
    }
    void whatIsMyOrder(){
        Primate::whatAmI(); // <-- SCOPE RESOLUTION OPERATOR
    }
};

-15
struct a{
 int x;

 struct son{
  a* _parent;
  void test(){
   _parent->x=1; //success
  }
 }_son;

 }_a;

int main(){
 _a._son._parent=&_a;
 _a._son.test();
}

संदर्भ उदाहरण।


2
आप को खुश कर सके संपादित क्यों / कैसे इस कोड को सवाल का जवाब की एक विवरण में? कोड-केवल उत्तर हतोत्साहित किए जाते हैं, क्योंकि उन्हें स्पष्टीकरण के साथ कोड से सीखना उतना आसान नहीं है। स्पष्टीकरण के बिना यह समझने में अधिक समय और प्रयास लगता है कि क्या किया जा रहा था, कोड में किए गए परिवर्तन, या यदि कोड उपयोगी है। उत्तर से सीखने की कोशिश करने वाले लोगों और उत्तर का मूल्यांकन करने वाले लोगों के लिए स्पष्टीकरण महत्वपूर्ण है, यह देखने के लिए कि क्या यह मान्य है, या मतदान के लायक है।
मकेन

3
यह उत्तर नेस्टेड कक्षाओं के बारे में है, जबकि प्रश्न व्युत्पन्न कक्षाओं के बारे में था (भले ही शब्द 'अभिभावक' और 'बच्चा' थोड़ा सा गलत हो) और इसलिए इस सवाल का जवाब बिल्कुल नहीं है।
जोहान्स मटोकिक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.