یکی از ویژگیهای کلیدی برنامه نویسی شیگرا، وراثت میباشد. وراثت شکلی از استفاده مجدد کلاسهای موجود است که طی آن برنامهنویس کلاسهای جدیدی را از کلاسهای موجود ایجاد میکند. کلاسهای جدید، دادهها و رفتارهای کلاس موجود را دارند و آنها را با قابلیتهای جدیدی توسعه میدهند. کلاس موجود را کلاس پایه یا پدر میگویند و کلاسی که صفات و رفتارهای کلاس پایه را به ارث میبرد، کلاس مشتق نامیده میشود. در این بخش مفاهیم مرتبط با شی گرایی در سی شارپ از جمله سطح دسترسی، خواص و کپسولهسازی به طور ساده گفته شده و سعی بر این است که ساختار این نوع برنامهنویسی مطرح شده و به مفاهیم پایه زیاد نپردازیم. با ما همراه باشید.
مفاهیم کلی شی گرایی در سی شارپ
سطح دسترسی (scope)
شاید با مطالعه بخش قبل آموزش، در این فکر باشید که کلمه کلیدی public چه کاربردی دارد؟ در مبحث شی گرایی در سی شارپ تعدادی کلمه کلیدی وجود دارد، که آنها سطح دسترسی فیلدها و متدها یک کلاس را تعیین میکنند. به این معنی که، متد یا فیلد تعریف شده در یک کلاس در چه مکانهایی از برنامه قابل دسترس و استفاده است. در جدول زیر چهار مورد از مهمترین سطوح دسترسی را با کاربرد آن مشاهده میکنید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
using System; namespace ConsoleApp1 { class Program { static void Main(string[] args) { Scope obj = new Scope(); obj.num = 1; obj.name = "Rasdino"; //Error } } class Scope { public int num; private string name; } } |
همانطور که در مثال بالا مشاهده میکنید. یک کلاس ساده تعریف کردهایم که یک فیلد از نوع public دارد. و در تابع main به آن دسترسی داشتهایم و به آن مقدار دادهایم. حال به همین کلاس یک فیلد دیگر با سطح دسترسی private اضافه میکنیم و مشاهده میشود که به آن در تابع main دسترسی نداریم.
کپسوله سازی (encapsulation)
کپسوله کردن یا مخفی کردن اطلاعات از دید کاربر، عملکردی است که در طی آن اطلاعات حساس یک موضوع از دید کاربر پنهان میشود. در تعریف یک کلاس تعدادی فیلد و متد ایجاد میشود. که برخی از اینها فقط برای کار با اعضا داخلی کلاس هستند و بنابراین لزومی ندارد که کاربر به آنها دسترسی داشته باشد. با یک مثال اهمیت این موضوع را نشان خواهیم داد.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
using System; namespace ConsoleApp1 { class Program { static void Main(string[] args) { Scope obj = new Scope(); obj.two = 4; Console.WriteLine(obj.MulByTwo(3)); } } class Scope { public int two = 2; public int MulByTwo(int num) { return num * two; } } } |
1 2 |
12 |
قطعه کد بالا را که نشان دهندۀ مفهوم کپسوله سازی (encapsulation) (یکی از مفاهیم مربوط به شی گرایی در سی شارپ ) است، بررسی میکنیم؛ در کلاس Scope بالا یک متد وجود دارد که وظیفه آن دو برابر کردن عدد ورودی است. اما به دلیل عدم توجه به مفهوم کپسوله کردن اطلاعات، برنامهنویس فیلد two را تغییر داده و عدد ورودی متد در عدد 4 ضرب شده و برنامه نتیجه دلخواه را نمیدهد. در نتیجه برای جلوگیری از این گونه اشتاباهات باید فیلدها یا متدهایی که برای کار با متدهای داخل کلاس هستند باید دارای سطح دسترسی مناسب شوند.
خواص (property)
خواص در #C استانداری برای دسترسی به اعضای دادهای یا فیلدها با سطح دسترسی private میباشد. اما در حقیقت کاربرد اصلی خواص، اعتبارسنجی مقادیر داده شده به فیلدها خواهد بود.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
private fieldType fieldName; //fieldType = propertyType public propertyType propertyName { get { return fieldName; } set { fieldName = value; } } |
در بالا نحوه اعلان یا تعریف خواص را ( در برنامهنویسی شی گرایی در سی شارپ ) مشاهده میکنید. propertyType باید همانند نوع فیلدی باشد که با آن در تماس است. propertyName طبق قرارداد، همان نام فیلد میباشد اما حرف اول آن بزرگ نوشته میشود. در داخل بلوک property دو بلوک get و set قراردارد. بلوک get برای دریافت مقدار فیلد و بلوک set برای تغییر مقدار فیلد استفاده میشود. برای ارزیابی مقدار اختصاص داده شده به فیلد باید از بلوک set همانند مثال زیر استفاده کرد.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
using System; namespace ConsoleApp1 { class Program { static void Main(string[] args) { MyClass obj = new MyClass(); obj.Num = 6; Console.WriteLine(obj.Num); } } class MyClass { private int num; public int Num { get { return num; } set { if (value > 0 && value < 10) { num = value; } else num = 0; } } } } |
1 2 |
6 |
در بلوک set مثال بالا، از دستور شرطی if استفاده کردهایم و از صفر تا ده را میتوانیم به num اختصاص دهیم. همانطور که گفته شد این مهمترین ویژگی خواص است. کلمه کلیدی value در داخل بلوک set، در واقع همان مقداری است که از طریق property به فیلد میخواهیم اختصاص دهیم.
1 2 |
object.propertyName = value; |
وراثت
قبل از شروع این قسمت باید خاطر نشان کنم که این مبحث از مهمترین مباحث شی گرایی در سی شارپ و البته همهی زبانهای برنامهنویسی دیگر میباشد. در واقع وراثت باعث میشود یک کلاس بتواند از فیلدها، خواص و متدهای کلاس دیگر استفاده کند. به طور پیشفرض همه کلاسها در #C از کلاس object ارث بری میکنند. همه فیلدها و متدهای کلاس پایه در کلاس مشتق قابل استفاده هستند به جز اعضایی که دارای سطح دسترسی private میباشند. در هنگام ایجاد شی از کلاس فرزند در ساختار وراثت، اول سازنده کلاس پدر اجرا میشود و بعد سازنده کلاس فرزند و این اتفاق در مخرب برعکس اجرا میشود. با مثال زیر این مفهوم بیشتر روشن خواهد شد.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
using System; namespace ConsoleApp1 { class Program { static void Main(string[] args) { Parent parent = new Parent(); Child child = new Child(); } } class Parent { public Parent() { Console.WriteLine("This is Parent Constractor"); } } class Child : Parent { public Child() { Console.WriteLine("This is Child Constractor"); } } } |
1 2 3 4 |
This is Parent Constractor This is Parent Constractor This is Child Constractor |
در مثال بالا، یک شی از کلاس پدر و یک شی از کلاس فرزند ایجاد کردهایم. در هنگام ایجاد شی از کلاس پدر فقط سازنده کلاس پدر اجرا شده است. اما در هنگام ایجاد شی از کلاس فرزند اول سازنده کلاس پدر و بعد سازنده کلاس فرزند اجرا شده است.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
using System; namespace ConsoleApp1 { class Program { static void Main(string[] args) { Child child = new Child("Bill", "Gates"); child.Print(); } } class Parent { private string firstName; private string lastName; public Parent(string firstName, string lastName) { this.firstName = firstName; this.lastName = lastName; } public void Print() { Console.WriteLine($"I am {this.firstName} {this.lastName}."); } } class Child : Parent { public Child(string firstName, string lastName) : base(firstName, lastName) { } } } |
اگر در کلاس مشتق سازنده کلاس پدر مقداردهی نشود کامپایلر خطا میدهد و باید همانند مثال بالا با استفاده از کلمه کلیدی base پارامترهای سازنده کلاس پایه مقداردهی شوند و برای ارثبری از یک کلاس باید نام کلاس پایه را بعد از علامت کالن (:) بعد از نام کلاس مشتق بیاوریم.
1 2 |
class classChild : classParent |
در این مثال یک شی از کلاس child ساختهایم و از طریق آن سازنده کلاس پایه را مقداردهی کردهایم. و باعث استفاده از متد به ارث برده شده Print، فیلدهای firstName و lastName که در واقع همان آرگومان های سازنده هستند را نشان دادهایم.
سطح دسترسی protected
این سطح دسترسی باعث میشود اعضا فقط در کلاس پایه (تعریف شده در آن) و کلاسهای مشتق شده از آن کلاس، قابل دسترس باشند و طبیعتا کلاسهایی که از این کلاس مشتق نشدهاند، به این اعضا دسترسی ندارند. مثال زیر این مفهوم را کاملا روشن میکند.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
using System; namespace ConsoleApp1 { class Program { static void Main(string[] args) { Parent obj = new Parent(); obj.publicField = "Accessible"; //obj.privateField = "inAccessible"; //obj.protectedField = "inAccessible"; } } class Parent { public string publicField; private string privateField; protected string protectedField; } class Child : Parent { public Child() { publicField = "Accessible"; //privateField = "inAccessible"; protectedField = "Accessible"; } } } |
در این مثال سه فیلد در کلاس parent تعریف شدهاند، و در دسترس بودن آنها در تابع main و کلاس child با کلمههای Accessible و inAccessible مشخص شده است.
در این مطلب سعی شد مفاهیم وراثت، خواص و سطح دسترسی در برنامه نویسی به روش شی گرایی در سی شارپ بیان شود و به طور کامل مورد بحث قرار گیرد. در بخش بعدی آموزش به مفاهیم اعضای static ، متدهای مجازی و … میپردازیم.
برای آموزشهای بیشتر با رزدینو همراه باشید.