سلام
ضمن تایید صحبت های god of war 2 ، در ادامه توضیحی برای سوال دوم تان حاضر کرده بودم که چنین است:
توابع در ناحیه Code درون RAM یکبار بارگذاری میشوند و اشاره گر شی (Object) که تابع از آن اجرا میشود به عنوان یک آرگومان (توسط کامپایلر) به تابع پاس داده میشود که این آرگومان خاص با نام this میشناسیم و در تابع قابل استفاده است.
بدیهی است در این شرایط بارگذاری 100 نمونه شی از یک کلاس فقط معادل 100 برابر متغییر های همان کلاس + یک بار حافظه برای کدها خواهد بود.
شاید تنها تفاوت توابع static در این است که نیاز به این اشاره گر ندارند.
فراخوانی یک تابع از یک نمونه کلاس برابر با فراخوانی ساده یک متد با یک پارامتر ورودی برای نمونه آن کلاس است، نکته فقط وجود یک پارامتر مخفی برای همه توابع عضو است.
در زبان های آزاد (unsafe) مانند ++C هیچ محیط runtime ای وجود ندارد و هیچ کس هیچ کجا هیچ اطلاعاتی از نوع و مفهوم و تعداد متغییرها ندارند، درست مانند ندانستن طول آرایه، نوع متغییر و توابع و... هم کاملاً ناشناخته است.
چیزی که میخواهم بگویم آن است که با دانستن آدرس یک نقطه از RAM هیچ کس و نه خود سیستم نمیداند آن نقطه (*void) به یک عدد اشاره میکند یا به یک نمونه کلاس، یعنی تفاوت int با یک کلاس مشخص نیست و واقعاً هم فرقی ندارند! فقط اعدادی بی مفهوم در آن نقطه هستند و فقط و فقط کامپایلر در زمان کامپایل پروژه نوع (type) را میدانسته... اجازه دهید مثالی ببینیم:
کد:
برای مشاهده محتوا ، لطفا وارد شوید یا ثبت نام کنید
خیلی جالب است دقت کنید، از دید شی گرایی Class1 و Class2 و int هیچ وجه اشتراک و قابلیت تبدیل و نگاشت و... ندارند ولی از نظر مدل و چیدمان عناصر حافظه ++C هیچ تفاوتی بین Class1 و Class2 و int وجود ندارد! یعنی هر سه به یک شکل و قالب از RAM استفاده میکنند، هیچ سربار داده های اضافه وجود ندارد و با یک بیدقتی کوچک راحت میتوان آنها را بجای یکدیگر استفاده کرد! (چه مثبت و چه منفی)
با داشتن اشاره گر خام نقطه RAM (همان *void) کامپایلر هم نوع را گم میکند و تنها کسی که نوع را میدانست هم کنار میرود، در نتیجه خیلی راحت میتوان RAM تخصیص داده شده برای یک class را به یک struct نگاشت کرد و یا بلعکس و هیچ اتفاقی هم رخ نمیدهد! حتی تابع sum هم به راحتی Class اش را میفروشد و امکاناتش را نثار یک RAM تخصیص داده شده برای int (متغییر x) میکند، یعنی کامپایلر یک نقطه RAM را به عنوان this به sum داده و sum هم بدون هیچ فهم و درکی ، آن عدد را شروع Class1 خودش فرض میکند و روی آن کار انجام میدهد.
در همچین زبانی، مهم فقط و فقط عدد شروع نقطه RAM است + فهم زمان کامپایل از نوع متغییر اشاره شده توسط این عدد(اشاره گر) ولاغیر.
برای پیاده سازی شی گرایی و override و... هم فقط جدولی وجود دارد که شامل آدرس توابع است و این جدول (اشاره گرتوابع) در مشتق ها بروز میشود.
در اینجا جالب است به واسط IUnknown و IDispatch هم اشاره کنم که در دنیای COM که کمی قانون مندی را اجباری میکنند، و مسئول تبدیل نام های توابع به آدرس توابع و بازگرداندن ساختار کلاس ها و شمارش تعداد ارجاع و... بوده اند.
در ادامه شاید بد نباشد به زبان تخصصی خودم هم اشاره ای کنم...
این وضعیت در زبان هایی امن (safe) مانند
[ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
و Java کمی (خیلی کم) متفاوت است، این زبان ها بیشترین حد مطالب را نگه داری میکنند و در زمان اجرا هم در اختیار قرار میدهند که میتوان نمود این کاتالوگ های متادیتایی را در قابلیتی بسیار جالب مانند Reflection مشاهده کرد.
در اینجا با داشتن متغییر یک شی در runtime میتوان قطعی گفت آن چه شی از چه نوعی است و چه توابع و خصایص و رویداد و... و... دارد.
در
[ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
قبل از دیتای اصلی کلاس یک اشاره گر شی نوع داده (System.Type) قرار دارد، یعنی مانند آن است که بگویم هر کلاسی در
[ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
یک متغییر حتمی و مخفی از نوع System.Type دارد.
یعنی یکی شی اصلی و یک شی نمونه سازی شده System.Type به حالت singleton (تک نمونه در کل برنامه)، دقت کنید که شی دوم هربار new نمیشود و حافظه گیری آن برای تعریف یک نمونه کلاس و 100 نمونه یک کلاس فرقی ندارد این همان اشاره گری است که با کلمه کلیدی typeof و یا متد GetType قابل دریافت است.
یعنی اگر اشاره گر نهایی کلاس را به دست آوریم برای خواندن دیتای آن باید IntPtr.Size بایت به جلو پیش برویم.
درضمن اگر گمراه نشوید باید عرض کنم که اشاره گرهای دات نت همه دوگانه هستند (**void) که خود مزیت های زیادی به همراه دارد که بماند...
کد:
برای مشاهده محتوا ، لطفا وارد شوید یا ثبت نام کنید
دقت کنید که بدلیل مکانیزم هایی مانند defragment هرلحظه امکان دارد مکان یک شی یا داده در حافظه CLR جابجا شود (به کمک **void) پس دستوراتی مانند آنچه در فوق دیدید با دقت فراوان باید استفاده شوند و موارد متعددی برای تضمین عملکرد آنها باید رعایت شود که گمانم در بحث تاپیک خارج است و بجز موارد بسیار بسیار بسیار خاص کاربردی در برنامه های عادی
[ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
ندارد و باید از این کدنویسی پرهیز کرد.
موفق باشید.