আমার কি স্পষ্টভাবে বেস ভার্চুয়াল ডেস্ট্রাক্টর কল করতে হবে?


350

সি ++ (কোনও ভার্চুয়াল ডেস্ট্রাক্টর সহ) ক্লাসকে ওভাররাইড করার সময় আমি উত্তরাধিকারী বর্গের ভার্চুয়াল হিসাবে আবার ডেস্ট্রাক্টরকে বাস্তবায়ন করছি, তবে আমাকে কি বেস ডিস্ট্রাক্টর বলা দরকার?

যদি তা হয় তবে আমি ভাবছি এটি এমন কিছু ...

MyChildClass::~MyChildClass() // virtual in header
{
    // Call to base destructor...
    this->MyBaseClass::~MyBaseClass();

    // Some destructing specific to MyChildClass
}

আমি কি সঠিক?

উত্তর:


469

না, নির্মাণের বিপরীত ক্রমে ধ্বংসকারীদের স্বয়ংক্রিয়ভাবে ডাকা হয়। (বেস ক্লাস শেষ)। বেস শ্রেণীর ধ্বংসকারীদের কল করবেন না।


খাঁটি ভার্চুয়াল ধ্বংসকারীদের কী হবে? আমার লিঙ্কারটি আমার উত্তরাধিকার সূত্রে প্রাপ্ত শ্রেণীর নন-ভার্চুয়াল বিনাশকটির শেষে এটি কল করার চেষ্টা করছে;
সিজেকিরি

40
দেহ ছাড়া আপনার খাঁটি ভার্চুয়াল ডেস্ট্রাক্টর থাকতে পারে না। শুধু খালি দেহ দিন। একটি নিয়মিত খাঁটি ভার্চুয়াল পদ্ধতিতে ওভাররাইডিং ফাংশন পরিবর্তে ডেকে আনা হয়, ধ্বংসকারীদের সাথে, তাদের সবাইকে ডাকা হয়, সুতরাং আপনাকে একটি শরীর সরবরাহ করতে হবে। = 0 এর অর্থ হ'ল এটি অবশ্যই ওভাররাইড করা উচিত, সুতরাং আপনার যদি এটির প্রয়োজন হয় তবে একটি দরকারী নির্মাণ।
লু ফ্রাঙ্কো

1
এই প্রশ্নটি সম্পর্কিত হতে পারে এবং প্রশ্নগুলির সহায়তা করতে পারে / 15265106 / সিএ-মিসিং-ভিটেবল-ত্রুটি
পল-সেবাস্তিয়ান মানোলে

কেন নিক বোল্টনের কোড সেগমেন্টেশন ত্রুটি সৃষ্টি করে না যদিও এটি বেস ডিস্ট্রাক্টরকে দু'বার কল deleteকরে যখন বেস ক্লাসে পয়েন্টারটিতে দু'বার ফোন করে সেগমেন্টেশন ত্রুটি সৃষ্টি করে?
ম্যাগগিরো

2
আপনার কোনও ভুল কোডের সাথে বিভাজন ত্রুটি নেই ed এছাড়াও, একজন ডেস্ট্রাক্টরকে কল করা স্মৃতি ছেড়ে দেয় না।
লু ফ্রাঙ্কো

92

আপনার বেজ ডিস্ট্রাক্টরকে কল করার দরকার নেই, একটি বেস ডেস্ট্রাক্টর সর্বদা ডাইরেক্ট ডেস্ট্রাক্টর দ্বারা আপনার জন্য ডাকা হয়। ধ্বংসের আদেশের জন্য দয়া করে এখানে আমার সম্পর্কিত উত্তর দেখুন

আপনি কেন বেস ক্লাসে ভার্চুয়াল ডেস্ট্রাক্টর চান তা বুঝতে, দয়া করে নীচের কোডটি দেখুন:

class B
{
public:
    virtual ~B()
    {
        cout<<"B destructor"<<endl;
    }
};


class D : public B
{
public:
    virtual ~D()
    {
        cout<<"D destructor"<<endl;
    }
};

যখন তুমি কর:

B *pD = new D();
delete pD;

তারপরে যদি আপনার বিতে ভার্চুয়াল ডেস্ট্রাক্টর না থাকে তবে কেবল ~ বি () কল করা হবে। তবে যেহেতু আপনার ভার্চুয়াল ডেস্ট্রাক্টর রয়েছে, তাই প্রথমে ~ D () বলা হবে, তারপরে ~ বি ()।


20
প্রোগ্রাম (ছদ্ম) আউটপুট অন্তর্ভুক্ত করুন। এটি পাঠককে সহায়তা করবে।
কুলদীপ সিং Dhaka


27

অন্যরা কী বলেছে, তবে এটিও নোট করুন যে উত্সযুক্ত শ্রেণিতে আপনাকে ডেস্ট্রাক্টর ভার্চুয়াল ঘোষণা করতে হবে না। আপনি যখন কোনও বিকাশকারী ভার্চুয়াল ঘোষণা করলেন, আপনি বেস ক্লাসে যেমন করেন তেমন সমস্ত উদ্ভূত ডেস্ট্রাক্টর আপনি সেগুলি ঘোষণা করেন বা না তা ভার্চুয়াল হবে। অন্য কথায়:

struct A {
   virtual ~A() {}
};

struct B : public A {
   virtual ~B() {}   // this is virtual
};

struct C : public A {
   ~C() {}          // this is virtual too
};

1
~ বি ভার্চুয়াল ঘোষিত না হলে কী হবে? ~ সি এখনও ভার্চুয়াল?
উইল

5
হ্যাঁ. যখন কোনও ভার্চুয়াল পদ্ধতি (কোনও, কেবল ধ্বংসকারী নয়) ভার্চুয়াল হিসাবে ঘোষণা করা হয়, উত্পন্ন শ্রেণিতে এই পদ্ধতির সমস্ত ওভাররাইড স্বয়ংক্রিয়ভাবে ভার্চুয়াল হয়। এই ক্ষেত্রে, আপনি ~ বি ভার্চুয়াল ঘোষণা না করলেও এটি এখনও আছে এবং ~ সে।
বালক

1
তবে বেস ক্লাসে তাদের অনুরূপ পদ্ধতির একই নাম এবং প্যারামিটারগুলির সাথে থাকা অন্য ওভাররাইড পদ্ধতিগুলির বিপরীতে ডিস্ট্রাক্টরের নামটি আলাদা W এটি কি ব্যাপার? @ বয়সি
ইউয়ান ওয়েন

1
@ ইউয়ানউইন এটি হবেনা, প্রাপ্ত (একমাত্র এবং একমাত্র) উদ্ভাবক সর্বদা তার বেস শ্রেণীর (একমাত্র এবং একমাত্র) ডেস্ট্রাক্টরকে ওভাররাইড করে।
বালক

10

নং অন্যান্য ভার্চুয়াল পদ্ধতিগুলির বিপরীতে, যেখানে আপনি স্পষ্টভাবে ডেরাইভড থেকে 'চেইনে' বেস পদ্ধতিটি কল করবেন, সংকলক বিপরীত ক্রমে ডিস্ট্রাক্টরকে কল করার জন্য কোড তৈরি করে যেখানে তাদের নির্মাণকারীদের ডাকা হত।


9

না, আপনি কখনই বেস ক্লাসের ডেস্ট্রাক্টরকে কল করেন না, এটি সর্বদা স্বয়ংক্রিয়ভাবে বলা হয় যেমন অন্যরা উল্লেখ করেছে তবে এখানে ফলাফল সহ ধারণার প্রমাণ রয়েছে:

class base {
public:
    base()  { cout << __FUNCTION__ << endl; }
    ~base() { cout << __FUNCTION__ << endl; }
};

class derived : public base {
public:
    derived() { cout << __FUNCTION__ << endl; }
    ~derived() { cout << __FUNCTION__ << endl; } // adding call to base::~base() here results in double call to base destructor
};


int main()
{
    cout << "case 1, declared as local variable on stack" << endl << endl;
    {
        derived d1;
    }

    cout << endl << endl;

    cout << "case 2, created using new, assigned to derive class" << endl << endl;
    derived * d2 = new derived;
    delete d2;

    cout << endl << endl;

    cout << "case 3, created with new, assigned to base class" << endl << endl;
    base * d3 = new derived;
    delete d3;

    cout << endl;

    return 0;
}

আউটপুটটি হ'ল:

case 1, declared as local variable on stack

base::base
derived::derived
derived::~derived
base::~base


case 2, created using new, assigned to derive class

base::base
derived::derived
derived::~derived
base::~base


case 3, created with new, assigned to base class

base::base
derived::derived
base::~base

Press any key to continue . . .

যদি আপনি বেস ক্লাসের ডেস্ট্রাক্টরকে ভার্চুয়াল হিসাবে কোনটি সেট করা উচিত সেট করে থাকেন, তবে কেস 3 ফলাফল কেস 1 এবং 2 এর মতো হবে।


ভাল চিত্রণ। আপনি যদি উত্পন্ন শ্রেণি থেকে বেস ক্লাসের ডেস্ট্রাক্টরকে কল করার চেষ্টা করেন তবে আপনার "ত্রুটি: 'বেস :: বিএএসই ()' <নিউইলাইন> A বেস () এর কল করার জন্য কোনও মিলবে না; কমপক্ষে আমার জি ++ 7.x সংকলকটির আচরণ।
কেমিন ঝো

6

না। এটি স্বয়ংক্রিয়ভাবে বলা হয়।


1

সি ++ এ বিক্ষোভকারীরা কেবল ভিত্তি শ্রেণীর ডেস্ট্রাক্টর ঘোষিত হলেই তাদের নির্মাণের ক্রমানুসারে স্বয়ংক্রিয়ভাবে ডাকা হয় (তত্কালীন ভিত্তি প্রাপ্ত হয়)virtual

যদি তা না হয় তবে অবজেক্ট মোছার সময় কেবলমাত্র বেস ক্লাসের ডেস্ট্রাক্টরকে ডাকা হবে।

উদাহরণ: ভার্চুয়াল বিনাশক ছাড়াই

#include <iostream>

using namespace std;

class Base{
public:
  Base(){
    cout << "Base Constructor \n";
  }

  ~Base(){
    cout << "Base Destructor \n";
  }

};

class Derived: public Base{
public:
  int *n;
  Derived(){
    cout << "Derived Constructor \n";
    n = new int(10);
  }

  void display(){
    cout<< "Value: "<< *n << endl;
  }

  ~Derived(){
    cout << "Derived Destructor \n";
  }
};

int main() {

 Base *obj = new Derived();  //Derived object with base pointer
 delete(obj);   //Deleting object
 return 0;

}

আউটপুট

Base Constructor
Derived Constructor
Base Destructor

উদাহরণ: বেস ভার্চুয়াল ডেস্ট্রাক্টর সহ

#include <iostream>

using namespace std;

class Base{
public:
  Base(){
    cout << "Base Constructor \n";
  }

  //virtual destructor
  virtual ~Base(){
    cout << "Base Destructor \n";
  }

};

class Derived: public Base{
public:
  int *n;
  Derived(){
    cout << "Derived Constructor \n";
    n = new int(10);
  }

  void display(){
    cout<< "Value: "<< *n << endl;
  }

  ~Derived(){
    cout << "Derived Destructor \n";
    delete(n);  //deleting the memory used by pointer
  }
};

int main() {

 Base *obj = new Derived();  //Derived object with base pointer
 delete(obj);   //Deleting object
 return 0;

}

আউটপুট

Base Constructor
Derived Constructor
Derived Destructor
Base Destructor

বেস শ্রেণীর ধ্বংসকারীকে virtualঅন্যথায় হিসাবে ঘোষণা করার পরামর্শ দেওয়া হয় , এটি অনির্ধারিত আচরণের কারণ হয়।

তথ্যসূত্র: ভার্চুয়াল ধ্বংসকারী

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