C++ Virtual Functions

در C++، Virtual Function (تابع مجازی) به تابعی در کلاس پایه گفته میشه که با کلمهٔ کلیدی virtual تعریف میشه و این امکان رو میده که نسخهٔ کلاس مشتق در زمان اجرا صدا زده بشه—even وقتی که از طریق اشاره‌گر یا مرجع به کلاس پایه با شیء کار می‌کنیم.

🔹 چرا Virtual Function؟

بدون virtual، وقتی یک تابع هم‌نام در کلاس مشتق تعریف کنیم، نوع اشاره‌گر تعیین می‌کنه کدوم تابع اجرا بشه (نه نوع شیء).
با virtual، نوع واقعی شیء در زمان اجرا مشخص می‌کنه کدوم تابع صدا زده بشه.
این همون Run-time Polymorphism یا Dynamic Dispatch است.

🔸 مثال پایه

#include <iostream> using namespace std; class Animal { public: virtual void sound() { // تابع مجازی cout << "Some generic sound" << endl; } }; class Dog : public Animal { public: void sound() override { // override اختیاری ولی توصیه‌شده cout << "Woof!" << endl; } }; int main() { Animal* a; // اشاره‌گر به کلاس پایه Dog d; a = &d; a->sound(); // ✅ خروجی: Woof! (نسخه‌ی Dog) return 0; }

اگر virtual رو حذف کنیم، خروجی میشه:

Some generic sound

🔹 رفتار سازنده و مخرب (Constructor/Destructor)

  • سازنده‌ها هرگز virtual نیستند؛ همیشه سازندهٔ کلاس پایه قبل از مشتق اجرا میشه.

  • Destructor اگه کلاس پایه به‌صورت چندریختی استفاده میشه باید virtual باشه تا مخرب کلاس مشتق هم فراخوانی بشه.

class Base { public: virtual ~Base() { cout << "Base destroyed\n"; } };

🔹 جدول مجازی (vtable)

کامپایلر برای هر کلاس حاوی توابع مجازی یک جدول اشاره‌گر (vtable) می‌سازه که در زمان اجرا آدرس تابع صحیح رو پیدا می‌کنه.
این باعث میشه هزینهٔ کمی در حافظه و زمان فراخوانی ایجاد بشه.

🔹 Pure Virtual Function و کلاس Abstract

اگه بخوایم تابعی رو الزاماً در کلاس مشتق پیاده‌سازی کنیم:

class Shape { public: virtual void draw() = 0; // pure virtual };
  • هر کلاسی که حداقل یک pure virtual داشته باشه، Abstract Class حساب میشه و نمی‌تونیم ازش شیء بسازیم:

    // Shape s; ❌ خطا

🔹 نکات کلیدی

  • virtual فقط در کلاس‌های پایه به‌کار میره.

  • میشه زنجیره‌ای از ارث‌بری داشت و همچنان Virtual Function عمل می‌کنه.

  • برای اطمینان از Override صحیح، از کلیدواژهٔ override در کلاس مشتق استفاده کنید.

  • اگر تابع کلاس پایه virtual باشه، تابع کلاس مشتق هم به‌صورت خودکار virtual است حتی اگر دوباره ننویسیم.

خلاصه:
Virtual Function به شما امکان میده یک رابط واحد (مثلاً ()sound) برای رفتارهای مختلف در کلاس‌های مشتق داشته باشید، و انتخاب نسخهٔ صحیح تابع در زمان اجرا انجام میشه.