আমি যদি কোনও বেস ক্লাসের ভার্চুয়াল ফাংশনটিকে ওভাররাইড করি তবে কল করতে পারি?


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()বাক্য গঠন আছে। এটি কি সি ++ এ সম্ভব?



1
গুগলারের জন্য: মনে রাখবেন যে আপনার কাছে এমন একটি সমস্যা থাকতে পারে যেমন আমি ক্লাস সদস্যের ভেরিয়েবল হিসাবে এটি সংরক্ষণ করি যা পয়েন্টার নয়। আমার উত্তর এখানে দেখুন: stackoverflow.com/questions/4798966/… আমি ঠিক করতে নতুন / মোছা জড়িত।
অ্যান্ড্রু

উত্তর:


449

সি ++ সিনট্যাক্সটি এরকম:

class Bar : public Foo {
  // ...

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

11
এটি করে কোন সম্ভাব্য সমস্যা আছে? এটা কি খারাপ অভ্যাস?
রববেন_ফোর্ড_ ফ্যান_বয়

36
@ ডেভিড: না, এটি করা একেবারে স্বাভাবিক, যদিও এটি যদি সত্যই কার্যকর হয় তবে এটি আপনার প্রকৃত শ্রেণীর উপর নির্ভর করে। আপনি ঘটতে চান এমন কিছু করলে কেবল বেস ক্লাসের পদ্ধতিটি কল করুন;)।
sth

20
আপনার ক্লায়েন্টদের এটি করার জন্য প্রয়োজনীয় হয়ে উঠলে এটি একটি কোড গন্ধ সাবধান ! (যাকে বলা হয় call super requirement: এটি এখানে চেক en.wikipedia.org/wiki/Call_super )
v.oddou

8
@ ভি.ডডু: সুপার ক্লাসটি কার্যকর হলে কল করার ক্ষেত্রে কোনও ভুল নেই। আপনি যে পৃষ্ঠাটি লিঙ্ক করেছেন সেটি হ'ল উত্তরাধিকারের সাথে জড়িত কিছু নির্দিষ্ট সম্ভাব্য সমস্যা। এমনকি এটি নিজেও বলেছে যে সাধারণভাবে সুপার ক্লাসকে কল করার ক্ষেত্রে কোনও ভুল নেই: "নোট করুন যে এটি পিতামাতাকে কল্পনা করার প্রয়োজন যা অ্যান্টি-প্যাটার্ন। প্রকৃত কোডে এমন অনেক উদাহরণ রয়েছে যেখানে সাবক্লাসের পদ্ধতিটি এখনও থাকতে পারে সুপারক্লাসের কার্যকারিতা চান, সাধারণত যেখানে এটি কেবল পিতামাতার কার্যকারিতা বৃদ্ধি করে। "
sth

26
এটি বেশিরভাগের কাছেই সুস্পষ্ট হতে পারে তবে সম্পূর্ণতার জন্য মনে রাখবেন যে এটি কখনও কনস্ট্রাক্টর এবং ডেস্ট্রাক্টরগুলিতে করবেন না।
টাইগারকডিং

123

হ্যাঁ,

class Bar : public Foo
{
    ...

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

এটি superজাভা হিসাবে একই , আপনি যখন একাধিক উত্তরাধিকার পেয়ে থাকেন তখন এটি বিভিন্ন ঘাঁটি থেকে কলিং বাস্তবায়নকে অনুমতি দেয় except

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
এটি নির্বাচিতটির চেয়ে ভাল উত্তর। ধন্যবাদ।
ম্যাড পদার্থবিজ্ঞানী

একাধিক উত্তরাধিকার? ওহ হায়!
লামিনো 16

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কাজ করতে সিনট্যাক্স ব্যবহার করতে হবে
টিটিমো

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

হ্যাঁ আপনি এটি কল করতে পারেন। শিশু শ্রেণিতে পিতামাতার ক্লাস ফাংশন কল করার জন্য সি ++ সিনট্যাক্স

class child: public parent {
  // ...

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

ফাংশন ওভাররাইডিং সম্পর্কে আরও পড়ুন ।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.