خواص (Property)
property (خصوصیت) استانداردی در ++C، برای دسترسی به اعضای دادهای (فیلدها) با سطح دسترسی private در داخل یک کلاس میباشد. همانطور که در درس قبل اشاره شد، تعریف فیلدها در داخل کلاس به صورت public اشتباه است، چون کاربران میتوانند با ایجاد یک شیء از کلاس به آنها دسترسی داشته باشند و هر مقداری که دوست دارند به آنها اختصاص دهند. برای رفع این مشکل مفهوم property ارائه شد. هر property دارای دو بخش میباشد، یک بخش جهت مقدار دهی (بلوک set) و یک بخش برای دسترسی به مقدار (بلوک get) یک داده private میباشد. property ها باید به صورت public تعریف شوند تا در کلاسهای دیگر نیز قابل دسترسی میباشند. در زیر نحوه تعریف و استفاده از property آمده است :
1: #include<string> 2: #include<iostream> 3: using namespace std; 4: 5: class Person 6: { 7: private: 8: string Name; 9: int Age; 10: double Height; 11: 12: public: 13: string getName() 14: { 15: return Name; 16: } 17: void setName(string value) 18: { 19: Name = value; 20: } 21: 22: int getAge() 23: { 24: return Age; 25: } 26: void setAge(int value) 27: { 28: Age = value; 29: } 30: 31: double getHeight() 32: { 33: return Height; 34: } 35: void setHeight(double value) 36: { 37: Height = value; 38: } 39: 40: public: 41: Person(string name, int age, double height) 42: { 43: this->Name = name; 44: this->Age = age; 45: this->Height = height; 46: } 47: }; 48: 49: int main() 50: { 51: Person person1("Jack", 21, 160); 52: Person person2("Mike", 23, 158); 53: 54: cout << "Name: " << person1.getName() << endl; 55: cout << "Age: " << person1.getAge() << " years old" << endl; 56: cout << "Height: " << person1.getHeight() << "cm" << endl; 57: 58: cout << endl; //Seperator 59: 60: cout << "Name: " << person2.getName() << endl; 61: cout << "Age: " << person2.getAge() << " years old" << endl; 62: cout << "Height: " << person2.getHeight() << "cm" << endl; 63: 64: person1.setName("Frank"); 65: person1.setAge(19); 66: person1.setHeight(162); 67: 68: person2.setName("Ronald"); 69: person2.setAge(25); 70: person2.setHeight(174); 71: 72: cout << endl; //Seperator 73: 74: cout << "Name: " << person1.getName() << endl; 75: cout << "Age: " << person1.getAge() << " years old" << endl; 76: cout << "Height: " << person1.getHeight() << "cm" << endl; 77: 78: cout << endl; 79: 80: cout << "Name: " << person2.getName() << endl; 81: cout << "Age: " << person2.getAge() << " years old" << endl; 82: cout << "Height: " << person2.getHeight() << "cm" << endl; 83: }
Name: Jack Age: 21 years old Height: 160cm Name: Mike Age: 23 years old Height: 158cm Name: Frank Age: 19 years old Height: 162cm Name: Ronald Age: 25 years old Height: 174cm
در برنامه بالا نحوه استفاده از property آمده است. همانطور که مشاهده میکنید در این برنامه ما سه فیلد (خطوط 10-8) تعریف کردهایم (سه فیلد با سطح دسترسی private).
string name; int age; double height;
دسترسی به مقادیر این فیلدها فقط از طریق property های ارائه شده (خطوط 38-13) امکان پذیر است.
string getName() { return Name; } void setName(string value) { Name = value; } int getAge() { return Age; } void setAge(int value) { Age = value; } double getHeight() { return Height; } void setHeight(double value) { Height = value; }
وقتی یک خاصیت ایجاد میکنیم، باید سطح دسترسی آن را public تعریف کرده و نوع دادهای را که بر میگرداند یا قبول میکند را، مشخص کنیم.
به کلمه value در داخل متد set توجه کنید. Value همان مقداری است که از طریق property به فیلد اختصاص میدهیم. برای اختصاص یک مقدار به یک فیلد از طریق property کافیست که از متدی که با کلمه set شروع شده است استفاده کنیم (کاری که در خطوط 80-64 انجام داده ایم). مثلاً برای اختصاص مقدار به سه فیلد age ،name و height از طریق property باید به صورت زیر عمل کنید :
person1.setName("Frank");
person1.setAge(19);
person1.setHeight(162);
دستورات بالا متد set مربوط به هر property را فراخوانی کرده و مقادیری به هر یک از فیلدها اختصاص میدهد. برای فراخوانی متدی که با حرف get شروع می شود کافیست که نام شیء و سپس علامت نقطه و در آخر نام متد دلخواه را بنویسیم. با این کار به برنامه میفهمانیم که ما نیاز به مقدار فیلد داریم.
cout << "Name: " << person1.getName() << endl; cout << "Age: " << person1.getAge() << " years old" << endl; cout << "Height: " << person1.getHeight() << "cm" << endl;
به این نکته توجه کنید که در داخل متدهایی که با کلمه get شروع می شوند هم میتوان تغییراتی بر روی فیلدها اعمال کرد. مثلاً فرض کنید که یک فیلد دارید که مقادیر پولی را در خود ذخیره میکند. شما میتوانید در متد get نحوه نمایش مقدار موجود در این فیلد را مشخص کنید. مثلاً خروجی به صورت سه رقم سه رقم نمایش داده شود. استفاده از property ها کد نویسی را انعطاف پذیر میکند مخصوصاً اگر بخواهید یک اعتبارسنجی برای اختصاص یک مقدار به فیلدها یا استخراج یک مقدار از آنها ایجاد کنید. پس میتوان گفت که :
مثلاً شما میتوانید یک محدودیت ایجاد کنید که فقط اعداد مثبت به فیلد age (سن) اختصاص داده شود. همانطور که در کد ابتدای درس مشاهده میکنید ما نوع فیلد age را int قرار دادهایم. یعنی کاربر میتواند هر رقمی بین اعداد 2147483648- تا 2147483647 را به این فیلد اختصاص دهد. ولی چون غیر معقولانه است و سن (age) باید یک عدد مثبت و از لحاظ عقلی عددی از 1 تا 100 باشد میتوانیم کاربر را با استفاده از بخش set مجبور کنیم که رقمی بین این دو عدد را به age اختصاص دهد. میتوانید با تغییر بخش set خاصیت Age این کار را انجام دهید :
int getAge() { return age; } void setAge(int value) { if (value > 0 && value <= 100) age = value; else age = 0; }
حال اگر کاربر بخواهد یک مقدار منفی به فیلد age اختصاص دهد مقدار age صفر خواهد شد. همچنین میتوان یک property فقط خواندنی (read-only) ایجاد کرد. این property فاقد بخش set است. به عنوان مثال میتوان یک خاصیت Name فقط خواندنی مانند زیر ایجاد کرد :
string getName() { return name; }
در این مورد اگر بخواهید یک مقدار جدید به فیلد name اختصاص دهید با خطا مواجه میشوید. نکته دیگری که باید به آن توجه کنید این است که شما میتوانید برای بخش set یا get سطح دسترسی ایجاد کنید. به تکه کد زیر توجه کنید :
public: string getName() { return name; } private: void setName(string value) { name = value; }
خاصیت Name فقط در خارج از کلاس قابل خواندن است اما متدها فقط داخل کلاس Person میتوانند مقادیر جدید بگیرند. یک property میتواند دارای دو فیلد باشد. به کد زیر توجه کنید :
__declspec(property (get = getFullName)) string FullName; string getFullName() { return firstName + " " + lastName ; }
همانطور که در مثال بالا مشاهده میکنید یک property فقط خواندنی تعریف کردهایم که مقدار برگشتی آن ترکیبی از دو فیلد firstName و lastName است که به وسیله فاصله از هم جدا شدهاند.