উত্তর:
এটি একটি ইন্টারফেসের জন্য আরও গুরুত্বপূর্ণ। আপনার শ্রেণীর যে কোনও ব্যবহারকারী সম্ভবত ইন্টারফেসের জন্য একটি পয়েন্টার ধরে রাখবেন, কংক্রিট বাস্তবায়নের কোনও পয়েন্টার নয়। যখন তারা এটি মুছতে আসে, ডেস্ট্রাক্টরটি যদি অ-ভার্চুয়াল হয়, তারা ইন্টারফেসের ডেস্ট্রাক্টরকে (বা সংকলক সরবরাহকৃত ডিফল্ট, যদি আপনি কোনও নির্দিষ্ট না করেন) কল করবেন, উত্পন্ন শ্রেণীর ডেস্ট্রাক্টরকে নয়। তাত্ক্ষণিক স্মৃতি ফুটো।
উদাহরণ স্বরূপ
class Interface
{
virtual void doSomething() = 0;
};
class Derived : public Interface
{
Derived();
~Derived()
{
// Do some important cleanup...
}
};
void myFunc(void)
{
Interface* p = new Derived();
// The behaviour of the next line is undefined. It probably
// calls Interface::~Interface, not Derived::~Derived
delete p;
}
[expr.delete]/
: ... if the static type of the object to be deleted is different from its dynamic type, ... the static type shall have a virtual destructor or the behavior is undefined. ...
। এটি উদ্ঘাটিত হবে যদি ডেরাইভড প্রকটভাবে উত্পন্ন উত্পাদক ব্যবহার করে।
আপনার প্রশ্নের উত্তর প্রায়শই হয় তবে সবসময় হয় না। যদি আপনার বিমূর্ত শ্রেণি ক্লায়েন্টদের কাছে এটির পয়েন্টারে কল করতে নিষেধ করে (বা এটি যদি তার ডকুমেন্টেশনে এটি বলে) তবে আপনি ভার্চুয়াল ডেস্ট্রাক্টর ঘোষণা না করতে পারেন।
আপনি ক্লায়েন্টদের এটির বিনষ্টককে সুরক্ষিত করে একটি পয়েন্টারে কল মুছতে নিষেধ করতে পারেন। এর মতো কাজ করা, ভার্চুয়াল ডেস্ট্রাক্টরকে বাদ দেওয়া পুরোপুরি নিরাপদ এবং যুক্তিসঙ্গত।
আপনি অবশেষে কোনও ভার্চুয়াল পদ্ধতির টেবিলটি শেষ করবেন না এবং আপনার ক্লায়েন্টকে এটির পয়েন্টারের মাধ্যমে এটি অ-মোছারযোগ্য করার বিষয়ে আপনার অভিপ্রায়টির সংকেত দেবেন, সুতরাং সেই পরিস্থিতিতে এটির ভার্চুয়াল ঘোষণা না করার আপনার পক্ষে যুক্তি রয়েছে।
[এই নিবন্ধে আইটেম 4 দেখুন: http://www.gotw.ca/publications/mill18.htm ]
আমি কিছু গবেষণা করার সিদ্ধান্ত নিয়েছি এবং আপনার উত্তরগুলি সংক্ষিপ্ত করার চেষ্টা করব। নিম্নলিখিত ধরণের প্রশ্নগুলি আপনাকে কী ধরণের ডেস্ট্রাক্টর দরকার তা সিদ্ধান্ত নিতে সহায়তা করবে:
আশা করি এটা কাজে লাগবে.
* এটি লক্ষ করা জরুরী যে C ++ এ কোনও শ্রেণিকে চূড়ান্ত হিসাবে চিহ্নিত করার উপায় নেই (যেমন নন সাবক্লাসেবল), তাই আপনি যদি আপনার ডেস্ট্রাক্টরকে অ-ভার্চুয়াল এবং সর্বজনীন ঘোষণা করার সিদ্ধান্ত নেন তবে আপনার সহকারী প্রোগ্রামারদের বিরুদ্ধে স্পষ্টভাবে সতর্ক করতে ভুলবেন না আপনার ক্লাস থেকে প্রাপ্ত।
তথ্যসূত্র:
হ্যাঁ এটি সর্বদা গুরুত্বপূর্ণ। উত্পন্ন ক্লাসগুলি মেমোরি বরাদ্দ করতে পারে বা অন্য সংস্থানগুলিতে রেফারেন্স ধরে রাখতে পারে যা অবজেক্টটি ধ্বংস হওয়ার পরে পরিষ্কার করতে হবে। আপনি যদি আপনার ইন্টারফেস / অ্যাবস্ট্রাক্ট ক্লাস ভার্চুয়াল ডেস্ট্রাক্টর না দেন, তবে প্রতিবার যখন আপনি একটি বেস ক্লাসের মাধ্যমে কোনও উত্পন্ন শ্রেণীর উদাহরণ মুছবেন তখন আপনার উত্পন্ন শ্রেণীর ডেস্ট্রাক্টরকে ডাকা হবে না।
অতএব, আপনি মেমরি ফাঁস হওয়ার সম্ভাবনা খুলছেন
class IFoo
{
public:
virtual void DoFoo() = 0;
};
class Bar : public IFoo
{
char* dooby = NULL;
public:
virtual void DoFoo() { dooby = new char[10]; }
void ~Bar() { delete [] dooby; }
};
IFoo* baz = new Bar();
baz->DoFoo();
delete baz; // memory leak - dooby isn't deleted
এটি সর্বদা প্রয়োজন হয় না , তবে আমি এটি ভাল অনুশীলন বলে মনে করি। এটি কী করে, এটি কোনও ডাইরেক্ট অবজেক্টকে বেস টাইপের পয়েন্টারের মাধ্যমে নিরাপদে মোছার অনুমতি দেয়।
উদাহরণস্বরূপ:
Base *p = new Derived;
// use p as you see fit
delete p;
অসুস্থ গঠিত যদি Base
একটি ভার্চুয়াল বিনাশকারী নেই কারণ এটি বস্তু মুছে ফেলতে যেমন যদি এটি একটি ছিল প্রচেষ্টা করা হবে Base *
।
shared_ptr
অবজেক্টটি মুছে ফেলার চেষ্টা করবে যেন এটি ছিল Base *
- এটি আপনি এটি তৈরি করেছেন এমন জিনিসটির কথা মনে পড়ে। রেফারেন্সযুক্ত লিঙ্কটি দেখুন, বিশেষত সেই বিটটিতে যা বলে যে "ডিস্ট্রাক্টর একই পয়েন্টার দিয়ে মুছতে কল করবে, মূল ধরণের সাথে সম্পূর্ণ হবে, এমনকি টিতে ভার্চুয়াল ডেস্ট্রাক্টর না থাকলেও বা শূন্য থাকে।"
এটি কেবল ভাল অনুশীলনই নয়। এটি কোনও শ্রেণি শ্রেণিবিন্যাসের জন্য নিয়ম # 1।
এখন কেন। সাধারণ প্রাণীক্রমক্রম নিন। ভার্চুয়াল ডেস্ট্রাক্টররা অন্য কোনও পদ্ধতি কল হিসাবে ভার্চুয়াল প্রেরণের মধ্য দিয়ে যায়। নিচের উদাহরণটি ধরুন।
Animal* pAnimal = GetAnimal();
delete pAnimal;
ধরে নিন যে অ্যানিম্যাল একটি বিমূর্ত শ্রেণি। সি ++ সঠিক কল করতে ডাস্টস্ট্রাক্টরকে জানার একমাত্র উপায় হ'ল ভার্চুয়াল পদ্ধতি প্রেরণের মাধ্যমে। যদি ডেস্ট্রাক্টর ভার্চুয়াল না হয় তবে এটি কেবলমাত্র অ্যানিমাল ডেস্ট্রাক্টরকে কল করবে এবং ডাইরেক্ট ক্লাসে কোনও বস্তু ধ্বংস করবে না।
বেস ক্লাসে ডেস্ট্রাক্টরকে ভার্চুয়াল করার কারণ হ'ল এটি উদ্ভূত শ্রেণীর থেকে পছন্দটিকে সরিয়ে দেয়। তাদের ডেস্ট্রাক্টর ডিফল্টভাবে ভার্চুয়াল হয়ে যায়।
উত্তরটি সহজ, আপনার এটি ভার্চুয়াল হতে হবে অন্যথায় বেস শ্রেণিটি সম্পূর্ণ পলিমারফিক ক্লাস নয়।
Base *ptr = new Derived();
delete ptr; // Here the call order of destructors: first Derived then Base.
আপনি উপরের মুছে ফেলা পছন্দ করবেন, তবে যদি বেস শ্রেণীর ডেস্ট্রাক্টর ভার্চুয়াল না হয় তবে কেবলমাত্র বেস শ্রেণীর ডেস্ট্রাক্টরকে কল করা হবে এবং উত্পন্ন শ্রেণীর সমস্ত ডেটা অপসারণযোগ্য থাকবে।
delete p
অনির্ধারিত আচরণের আহ্বান জানায়। এটি কল করার নিশ্চয়তা নেইInterface::~Interface
।