ایران سرفراز- نرم افزار وپروژهای دانشجویی


نرم افزار وپروژهای دانشجویی

فصل سیزدهم Overloadکردن عملگرها در # C

<!-- /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:"Times New Roman";} @page Section1 {size:612.0pt 792.0pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:35.4pt; mso-footer-margin:35.4pt; mso-paper-source:0;} div.Section1 {page:Section1;} -->

فصل سیزدهم

C# کردن عملگرها در Overload

آنچه که در این فصل یاد خواهید گرفت:

کردن عملگرها overload − مفهوم

در انواع داد های تعریف شده توسط کاربر #C − استفاده از عملگرهای معمول زبان

operator − نحوه ی استفاده از کلمه ی کلیدی

کردن عملگرهای دوتایی و یکتایی Overload −

کردن عملگرهای تبدیل صریح و ضمنی Overload −

را #C این است که کلا س های تعریف شده توسط کاربر م ی توانند عملکرد انواع داد ه ی داخلی #C یکی از اهداف طراحی در

داشته باشند . برای مثال، فرض کنید که یک نوع داد ه برای نمایش کسرها تعریف کرد ه اید . این کلاس م ی تواند همه

توانایی های انواع داد ه ی داخلی را داشته باشد، یعنی شما قادر هستید عملیات ریاضی را روی نمون ه هایی از کسرهایتان انجام

و ... تبدیل کنید . می توانید متدهایی برای هر عمل پیاد ه سازی کنید و int دهید و کسرها را به انواع داد ه ی داخلی همچون

آنها را با نوشتن دستوراتی بصورت زیر فراخوانی کنید.

Fraction theSum = firstFraction.Add(secondFraction);

اگر چه این دستور کار می کند، ولی جالب نیست و شبیه استفاده ی انواع داده ی داخلی نیس ت . بهتر است بصورت زیر نوشته

شود.

Fraction theSum = firstFraction + secondFraction;

جمع می شوند. int این دستور با نحوه ی کارکرد انواع داد هی داخلی سازگار و مشهود است و همانند متغیرهای

در این فصل تکنی ک هایی برای اضاف ه کردن عملگرها به انواع داد ه ی تعریف شده توسط کاربر یاد خواهید گرف ت . همچنین

نحوه ی اضاف هکردن عملگرهای تبدیل صریح و ضمنی را یاد خواهید گرفت.

کردن عملگرها overload- فصل سیزدهم

179

operator -1-13 کاربرد کلمه ی کلیدی

می توانید عملگرها را با متدهای ایستایی که مقادیر بازگشتی آنها نتیج ه ی یک عمل را نشان م ی دهند پیاد ه سازی #C در

کنید، بطوریکه عملوندهای آنها همان پارامترها هستن د . زمانی که یک عملگر برای کلاسی ایجاد م ی کنید، گفته م ی شود آن

کردن عملگر + بصورت زیر خواهید نوشت: overload شده است. پس برای overload عملگر

public static Fraction operator+(Fraction lhs, Fraction rhs)

پارامتر اول عبارت سمت چپ عملگر م یباشد و پارامتر دوم عبارت سمت راست عملگر می باشد.

و به دنبال آن نام عملگر اس ت . کلمه ی operator کردن یک عملگر، نوشتن کلم ه ی کلیدی overload برای #C گرامر

را بنویسید. + operator ،+ کردن عملگر overload یک معرف متد است. پس برای operator کلیدی

زمانیکه عبارت زیر را م ینویسید:

Fraction theSum = firstFraction + secondFraction;

پارامتر دوم آن secondFraction پارامتر اول آن و firstFraction شده ی + احضار می شود که overload عملگر

خواهد شد. زمانی که کامپایلر عبارت زیر را م یبیند:

firstFraction + secondFraction

آن را به عبارت زیر ترجمه م یکند.

Fraction.operator+(firstFraction, secondFraction)

انتساب theSum بنام Fraction جدید برگردانده م ی شود که در این نمونه مقدار آن به شی Fraction در نتیجه، یک

داده می شود.

توجه: ایجاد عملگرهای غیر ایستا امکا نپذیر نیست و عملگرهای دوتایی باید دو عملوند داشته باشند.

NET. -2-13 پشتیبانی دیگر زبا نهای

همچون ) NET. کردن عملگرها را برای کلا س های شما فراهم م ی کند، اما بعضی از زبا ن های overload توانایی CLS در #C

کردن عملگرها را پشتیبانی نمیکنند. پس مطمئن شوید کلا سهای شما روش دیگری برای انجام VB.NET ) overload

را برای انجام همان ()Add کردید، بهتر است متد overload همین اعمال را پشتیب ا نی می کنند. پس اگر عملگر جمع + را

کار نیز اضافه کنید.

-3-13 ایجاد عملگرهای مفید

عمل م ی کند . ولی #C کردن عملگرها، کد شما را مشهو د تر می سازد و کد شما بیشتر شبیه انواع داد ه ی داخلی Overload

اگر شیوه ی معمول کاربرد عملگرها را دستکاری کنید، کد شما پیچیده و غیرقابل مدیریت خواهد ش د . از روش های جدید و

مزاجی در کاربرد عملگرها دوری کنید.

اضافه کنید، ولی این Employee برای مثال، اگرچه ممکن است عملگر ++ را برای افزایش حقوق ماهیان ه ی کارمند به کلاس

کردن عملگرها overload عملگر برای سروی س گیرندگان این کلاس سردرگمی عجیبی ایجاد م ی کند. بهتر است زمانی از

استفاده کنید که مفهوم آن کاملا واضح باشد.

Mohsen_mhayar@yahoo.com

180

-4-13 عملگرهای دوتایی منطقی

اصرار دارد در صورت #C . کردن عملگر تساوی (==) برای تست مساو ی بودن دو شی کاملا معمول اس ت Overload

شود . بطور مشابه، عملگرهای د و تایی (>)، overload کردن عملگر تساوی، بایستی عملگر نامساوی (=!) نیز overload

می شوند. overload (>=) بزرگتر از (<)، کوچتر مساوی (=>) و بزرگتر مساوی

-5-13 عملگر تساوی

را نیز object فراهم شد ه توسط ()Equals کنید، توصیه م ی شود متد مجازی overload اگر عملگر تساوی را

را NET. کنید و عملکرد آن را شبیه عملگر تساوی قرار دهی د . این عمل چندریختی و سازگاری با زبان های دیگر override

شده را بکار نخواهند بر د . اما انتظار دارید overload عملگرهای ____________FCL برای کلاس شما به ارمغان م ی آورد. کلاس های

را با نشان هی زیر پیاده سازی می کند. ()Equals متد object کلاس های شما متدهای اصلی را پیاده سازی کنند. کلاس

public virtual bool Equals(object o)

شما با اشیاء دیگر بصورت چندریختی عمل م ی کند . در داخل بدن ه ی Fraction کردن این متد، کلاس override با

باهم مقایسه می شوند. Fraction باید مطمئن شویم دو شی ،()Equals

public override bool Equals(object o)

{

if (! (o is Fraction) )

{

return false;

}

return this == (Fraction) o;

}

با یک o در صورتی که o is Fraction برای بررسی نوع یک شی در زمان اجرا استفاده م یشود. پس عبارت is عملگر

ارزیابی می شود. false در غیر اینصورت به ،true سازگار باشد به Fraction نمونه از

کنید. override را نیز ()GetHashCode کامپایلر انتظار دارد متد

-6-13 عملگرهای تبدیل

تبدیل کنی د . تبدیل از int را به long تبدیل م ی کند و به شما اجازه م ی دهد بطور صریح long را به int بطور ضمنی #C

قرار دا د . long را م ی توان در مقدار داد ه ای از نوع int ضمنی است و آن ایمن است، چون هر مقدار داد ه ی long به int

باید صریح باشد، چون ممکن است مقداری از اطلاعات از دست برود. (int به long عمل تبدیل بر عکس ( از

int myInt = 5;

myLong;

myLong = myInt; // implicit

myInt = (int) myLong; // explicit

باید همین عمل را برای کسرهایتان انجام دهی د . تبدیل ضمنی یک عدد صحیح به کسر امکان پذیر است، چون هر عدد

1). ولی تبدیل کسر به عدد صحیح باید بصورت صریح باش د . پس /15== صحیح معادل کسر همان عدد روی یک است ( 15

4 به مقدار صحیح 2 تبدیل گردد. / ممکن است مقدار کسری 9

در هنگام پیاد ه سازی تبدی ل های خود، در صورتی که م ی دانید عمل تبدیل هیچ داد ه ای را از بین نم ی برد کلم ه ی کلیدی

را بکار برید. explicit را بکار برید و در غیر اینصورت کلمه کلیدی implicit

را نشان م ی دهد. زمانی که Fraction 1 نحوه ی پیاده سازی تبدیل های صریح و ضمنی و بعضی از عملگرهای کلاس - مثال 13

پیاده سازی نشده است. ()GetHashCode این مثال را کامپایل م یکنید، تعدادی هشدار دریافت خواهید کرد، چون

کردن عملگرها overload- فصل سیزدهم

181

1- مثال 13

public class Fraction

{

private int numerator;

private int denominator;

public Fraction(int numerator, int denominator)

{

Console.WriteLine("In Fraction Constructor(int, int)");

this.numerator=numerator;

this.denominator=denominator;

}

public Fraction(int wholeNumber)

{

Console.WriteLine("In Fraction Constructor(int)");

numerator = wholeNumber;

denominator = 1;

}

public static implicit operator Fraction(int theInt)

{

Console.WriteLine("In implicit conversion to Fraction");

return new Fraction(theInt);

}

public static explicit operator int(Fraction theFraction)

{

Console.WriteLine("In explicit conversion to int");

return theFraction.numerator /theFraction.denominator;

}

public static bool operator==(Fraction lhs, Fraction rhs)

{

Console.WriteLine("In operator ==");

if (lhs.denominator == rhs.denominator &&lhs.numerator == rhs.numerator)

{

return true;

}

// code here to handle unlike fractions

return false;

}

public static bool operator !=(Fraction lhs, Fraction rhs)

{

Console.WriteLine("In operator !=");

return !(lhs==rhs);

}

public override bool Equals(object o)

{

Console.WriteLine("In method Equals");

if (! (o is Fraction) )

{

return false;

}

return this == (Fraction) o;

}

public static Fraction operator+(Fraction lhs, Fraction rhs)

{

Console.WriteLine("In operator+");

if (lhs.denominator == rhs.denominator)

{

return new Fraction(lhs.numerator+rhs.numerator,lhs.denominator);

}

// simplistic solution for unlike fractions

// 1/2 + 3/4 == (1*4) + (3*2) / (2*4) == 10/8

int firstProduct = lhs.numerator * rhs.denominator;

int secondProduct = rhs.numerator * lhs.denominator;

return new Fraction(

Mohsen_mhayar@yahoo.com

182

firstProduct + secondProduct,

lhs.denominator * rhs.denominator

);

}

public override string ToString( )

{

String s = numerator.ToString( ) + "/" +denominator.ToString( );

return s;

}

}

public class Tester

{

static void Main( )

{

Fraction f1 = new Fraction(3،4);

Console.WriteLine("f1: {0}", f1.ToString( ));

Fraction f2 = new Fraction(2،4);

Console.WriteLine("f2: {0}", f2.ToString( ));

Fraction f3 = f1 + f2;

Console.WriteLine("f1 + f2 = f3: {0}", f3.ToString( ));

Fraction f4 = f3 + 5;

Console.WriteLine("f3 + 5 = f4: {0}", f4.ToString( ));

Fraction f5 = new Fraction(2،4);

if (f5 == f2)

{

Console.WriteLine("F5: {0} == F2: {1}",f5.ToString( ),f2.ToString( ));

}

}

}

با دو سازنده شروع م ی شود: یکی صورت و مخرج را م ی گیرد و دیگری کل عدد را م ی گیرد. سازنده ها با Fraction کلاس

اعلان دو عملگر تبدیل دنبال می شوند. عملگر تبدیل اولی یک عدد صحیح را به یک کسر تبدیل م یکند:

public static implicit operator Fraction(int theInt)

{

return new Fraction(theInt);

}

تبدیل شود که صورت Fraction علامت گذاری می شود، چون هر عدد صحیح م ی تواند به ی ک implicit این تبدیل با

کسر همان عدد صحیح بوده و مخرج آن عدد یک م ی باشد. این مسئولیت را به سازند ه ای که یک عدد صحیح م ی گیرد واگذار

کنید.

ها به عدد صحیح است: Fraction عملگر تبدیل دوم، تبدیل صریح

public static explicit operator int(Fraction theFraction)

{

return theFraction.numerator /theFraction.denominator;

}

16 باشد، مقدار صفر بر م ی گرداند . / چون این مثال عمل تقسیم صحیح انجام م ی دهد، مقدار صحیح بر م ی گرداند. پس اگر 15

یک عملگر تبدیل پیچیده ممکن است عمل گرد کردن را انجام دهد.

عملگرهای تبدیل با عملگر تسا و ی (==) و عملگر نامساوی (=!) دنبال می شوند. بخاطر دارید که اگر یکی از این دو عملگر را

پیاده سازی کردید، باید دیگری را نیز پیاده سازی کنید.

4 و / بدین صورت است که صور ت ها و مخر ج ها باهم مطابقت داشته باشن د . به عنوان مثا ل : 3 Fraction تساوی مقدار یک

8/6 مساوی نی س تند. البته ممکن است در یک پیاد ه سازی این کسرها ساده شده و مساوی به حساب آین د . کلاس

کردن عملگرها overload- فصل سیزدهم

183

همه عملگرهای ریاضی ( جمع، تفریق، ضرب و تقسی م ) را پیاده سازی نمی کند. برای فهم ساد ه ی مطلب، فقط Fraction

عمل جمع بصورت بسیار ساده پیاد هسازی می شود. در صورت مساوی بودن مخرج ها، عمل جمع بصورت زیر انجام می شود:

public static Fraction operator+(Fraction lhs, Fraction rhs)

{

if (lhs.denominator == rhs.denominator)

{

return new Fraction(lhs.numerator+rhs.numerator,lhs.denominator);

}

اگر مخرج ها مساوی نباشند، با مخرج مشترک گرفتن (حاصلضرب هر دو مخرج) عمل جمع انجام می شود.

int firstProduct = lhs.numerator * rhs.denominator;

int secondProduct = rhs.numerator * lhs.denominator;

return new Fraction(firstProduct + secondProduct,lhs.denominator *

rhs.denominator);

4 را باهم جمع کنید، صورت کسر اول ( 1) در مخرج کسر دوم / 2 و 3 / این کد با یک م ثال بهتر فهمیده م ی شود. اگر بخواهید 1

ضرب شده و در یک متغیر ذخیره م ی شود( 4). می توانید صورت کسر دوم ( 3) را در مخرج کسر اول ( 2) ضرب کرده و در

متغیر دیگری ذخیره کنی د ( 6).می توانید مجموع دو متغیر را د ر صورت جواب قرار داده ( 10 ) و حاصلضرب دو مخرج را در

10 ) جواب صحیحی است. / مخرج جواب قرار دهید ( 8). کسر بدست آمده ( 8

کنید تا مقدار آن را در قالب رشت های مخرج/صورت برگرداند. override را ()ToString نهایتا، متد

public override string ToString()

{

String s = numerator.ToString() + "/" +denominator.ToString( );

return s;

}

4 آن را تست کنید. / 4 و 2 / را در دست دارید و برای آزمایش آماده است. با دو کسر ساده 3 Fraction حال کلاس

Fraction f1 = new Fraction(3،4);

Console.WriteLine("f1: {0}", f1.ToString());

Fraction f2 = new Fraction(2،4);

Console.WriteLine("f2: {0}", f2.ToString( ));

چاپ می شوند. ()WriteLine خروجی مورد انتظار ما در سازند هها بوسیله دستور

In Fraction Constructor(int, int)

f1: 3/4

In Fraction Constructor(int, int)

f2: 2/4

عملگر ایستای + را احضار م ی کند. هدف این عملگر جمع دو کسر و برگرداندن مجموع آنها در ،()Main خط بعدی در متد

یک کسر جدید است.

Fraction f3 = f1 + f2;

Console.WriteLine("f1 + f2 = f3: {0}", f3.ToString());

را نشان می دهد. + operator بررسی خروجی، نحو هی کار

In operator+

In Fraction Constructor(int, int)

f1 + f2 = f3: 5/4

دو مقدار صحیح صورت و مخرج کسر جدید را می گیرد. f احضار می شود و سپس سازنده ی 3 + operator

Fraction 3 اضافه م ی کند و مقدار نتیجه را به یک f بنام Fraction را به یک int یک عدد ()Main آزمایش بعدی در

4 انتساب می دهد. f جدید بنام

Fraction f4 = f3 + 5;

Mohsen_mhayar@yahoo.com

184

Console.WriteLine("f3 + 5: {0}", f4.ToString());

خروجی این قطعه کد، مراحل تبدی لهای مختلف را نشان می دهد.

In implicit conversion to Fraction

In Fraction Constructor(int)

In operator+

In Fraction Constructor(int, int)

f3 + 5 = f4: 25/4

احضار شده اس ت . در دستور برگشت از عملگر تبدیل Fraction توجه کنید ک ه عملگر تبدیل ضمنی برای تبدیل 5 به یک

3 به عملگر + رد f 5 را ایجاد م ی کند. این کسر جدید به همراه / فراخوانی م ی شود و کسر 1 Fraction ضمنی، سازنده ی

4 رد می شود. f می شوند و مجموع آنها به سازند هی کسر

2 است . اگر مساوی باشند، مقادیر آنها f 5) ایجاد م ی شود. آزمایش روی تساوی آن با f) در آزما یش نهایی یک کسر جدید

چاپ می شود.

Fraction f5 = new Fraction(2،4);

if (f5 == f2)

{

Console.WriteLine("F5: {0} == F2: {1}",f5.ToString( ),f2.ToString( ));

}

شده را نشان می دهد. overload 5 را نشان می دهد. سپس کار عملگر تساوی f خروجی این قطعه کد، ایجاد

In Fraction Constructor(int, int)

In operator ==

F5: 2/4 == F2: 2/4

-7-13 خلاصه

شده است. overload زمانی که یک عملگر برای کلاسی ایجاد می کنید، گفته می شود آن عملگر 􀂃

و به دنبال آن نام عملگر است. operator کردن یک عملگر، نوشتن کلمه ی کلیدی overload برای #C گرامر 􀂃

کردن عملگرها را پشتیبانی نمیکنند. پس اگر عملگر VB.NET ) overload همچون ) NET. بعضی از زبان های 􀂃

را برای انجام همان کار نیز اضافه کنید. ()Add کردید، بهتر است متد overload جمع + را

عمل #C کردن عملگرها، کد شما را مشهو د تر می سازد و کد شما بیشتر شبیه انواع داد ه ی داخلی Overload 􀂃

می کند.

را نیز object فراهم شده توسط ()Equals کنید، توصیه م ی شود متد مجازی overload اگر عملگر تساوی را 􀂃

کنید و عملکرد آن را شبیه عملگر تساوی قرار دهید. override

در هنگام پیاده سازی تبدی ل های خود، در صورتی که م ی دانید عمل تبدیل هیچ داد های را از بین نم ی برد کلم ه ی 􀂃

را بکار برید. explicit را بکار برید و در غیر اینصورت کلمه کلیدی implicit کلیدی

Mohsen_mhayar@yahoo.com

 

   + MOHSEN GHASEMI - ۱٢:٢٢ ‎ب.ظ ; ۱۳۸٩/٤/۱٥