কারণ
ভার্চুয়াল মেকানিজম কাজ করে শুধু তখনই যখন একটি বেস ক্লাস পয়েন্টার একটি ডেরাইভড ক্লাস অবজেক্টকে পয়েন্ট করে। কিন্তু কনস্ট্রাক্টর কল হওয়ার সময় অবজেক্ট এখনো পুরোপুরি তৈরি হয়নি — তাই vtable বা vptr এখনো মেমরিতে তৈরি হয়নি। ফলে কনস্ট্রাক্টরকে ভার্চুয়াল বানানো সম্ভব নয়।
ভার্চুয়াল ডেস্ট্রাক্টর সম্ভব কেন?
ডেস্ট্রাক্টর কল হওয়ার সময় অবজেক্ট পুরোপুরি তৈরি থাকে, vtable/vptr সক্রিয় থাকে। তাই ডাইনামিক ডিসপ্যাচ কাজ করে। এটি পলিমরফিক ডিলিশনের জন্য জরুরি।
উদাহরণ কোড
#include <iostream>
using namespace std;
class Base {
public:
Base() { cout << "Constructing Base\n"; }
virtual ~Base() { cout << "Destructing Base\n"; } // Virtual destructor
};
class Derived : public Base {
public:
Derived() { cout << "Constructing Derived\n"; }
~Derived() { cout << "Destructing Derived\n"; }
};
int main() {
Derived* d = new Derived();
Base* b = d;
delete b; // Virtual destructor দিয়ে Derived::~Derived() কল হবে
return 0;
}
আউটপুট
Constructing Base Constructing Derived Destructing Derived Destructing Base
বিকল্প: ভার্চুয়াল কনস্ট্রাক্টর প্যাটার্ন
যদি রানটাইমে টাইপ অনুযায়ী অবজেক্ট তৈরি করতে হয়, তবে Virtual Constructor Idiom বা Factory Method ব্যবহার করা হয়:
class Base {
public:
virtual Base* clone() const = 0; // Virtual copy constructor
virtual ~Base() {}
};
class Derived : public Base {
public:
Base* clone() const override { return new Derived(*this); }
};
ব্যাখ্যা
কনস্ট্রাক্টর অবজেক্ট তৈরি করে, তাই এটি ক্লাসের টাইপ জানতে হবে কম্পাইল টাইমে। ভার্চুয়াল ফাংশন হয় রানটাইমে রিজলভ। তাই কনস্ট্রাক্টর ভার্চুয়াল হতে পারে না। তবে ক্লোন বা ফ্যাক্টরি মেথড দিয়ে একই ফলাফল পাওয়া যায়।