PDA

View Full Version : مبتدی: چند ریختی زمان اجرا و لغو روش



قله بلند
جمعه 20 آذر 1388, 13:59 عصر
سلام
در برنامه اول به کمک ارث بری، چند ریختی زمان اجرا به وجود می آید.
//Using run-time polymorphism
class Figure
{
double dim1;
double dim2;
Figure(double a,double b)
{
dim1=a;
dim2=b;
}
double area()
{
System.out.println("Area for Figure is undifined");
return 0;
}
}
class R_ectangle extends Figure
{
R_ectangle(double a,double b)
{
super(a,b);
}
double area()
{
System.out.println("Inside Area for Rectangle");
return dim1*dim2;
}
}
class Triangle extends Figure
{
Triangle(double a,double b)
{
super(a,b);
}
double area()
{
System.out.println("Inside Area for Triangle");
return dim1*dim2/2;
}
}
public class FindAreas
{
public static void main(String args[])
{
Figure f=new Figure(10,10);
R_ectangle r=new R_ectangle(9,5);
Triangle t=new Triangle(10,8);
Figure figref;
figref=r;
System.out.println("Area is= "+figref.area());
figref=t;
System.out.println("Area is= "+figref.area());
figref=f;
System.out.println("Area is= "+figref.area());
}
}در اینجا مطلب جالب شد. تا الان می گفتیم که در ارث بری، کلاس پایه از کلاس مشتق شده خود بی خبر است ولی کلاس مشتق از توابع و متغیرهای تعریف شده در کلاس بالای خود با خبر است.
حالا، در اینجا باید یک شیئی از کلاس پایه تعریف کنیم و آدرس کلاس مشتق را به آن بدهیم تا بتوانیم به توابع هم نام دسترسی داشته باشیم.
مساله دیگر نیز این است که باید این توابع هم نام در کلاس پایه نیز تعریف شوند وگرنه خطا صادر می شود. من این خطا را دیدم.
حالا در برنامه دوم نیز به همان نتایج می رسیم. آیا در برنامه دوم دیگر نمی توانیم نام چند ریختی زمان اجرا را روی آن بگذاریم؟ باید نام آن را لغو روش بگذاریم؟
//Using run-time polymorphism
class Figure
{
double dim1;
double dim2;
Figure(double a,double b)
{
dim1=a;
dim2=b;
}
double area()
{
System.out.println("Area for Figure is undifined");
return 0;
}
}class R_ectangle extends Figure
{
R_ectangle(double a,double b)
{
super(a,b);
}
double area()
{
System.out.println("Inside Area for Rectangle");
return dim1*dim2;
}
}
class Triangle extends Figure
{
Triangle(double a,double b)
{
super(a,b);
}
double area()
{
System.out.println("Inside Area for Triangle");
return dim1*dim2/2;
}
}
public class FindAreas
{
public static void main(String args[])
{
Figure f=new Figure(10,10);
R_ectangle r=new R_ectangle(9,5);
Triangle t=new Triangle(10,8);
double x=f.area();
System.out.println(x);
double y=r.area();
System.out.println(y);
double z=t.area();
System.out.println(z); }
}

cups_of_java
جمعه 20 آذر 1388, 16:06 عصر
مثال دوم اصلن از پلی مورفیزم استفاده نکرده چون به طور مستقیم متد area رو روی هر کدام از اشیا صدا میکنه!

قله بلند
جمعه 20 آذر 1388, 18:21 عصر
پس می توانیم اینگونه بگوییم:
در هر دو کد از لغو روش استفاده شده.
در کد اول چند ریختی زمان اجرا را داریم ولی در کد دوم چند ریختی زمان کامپایل(یا کلاً نبود چند ریختی).
سوال: هدف کلی از لغو روش چیست؟ این را می دانم که کلاس پایه که قرار نیست همه کارهای کلاس های مشتق شده از خود را حدس بزند و انجام دهد. خود کلاس های مشتق باید بر حسب نیاز خود توابع و متغیرهای خود را تعریف کنند. همانطور که در هر دو برنامه می بینیم.
ولی سوال من اینجاست. چه لزومی دارد که تابع area در کلاس پایه تعریف شود. این تابع که کاری نمی کند. مگر هر کلاس مشتق دارای نیازهای شخصی و اساسی خود نیست. پس خودش تابع مورد نیازش را تعریف کند و استفاده کند. فوق اش دو تا متغیر نیاز است که در تمام کلاس های مشتق مشترک است که در کلاس پایه نیز تعریف می شود.

cups_of_java
جمعه 20 آذر 1388, 22:21 عصر
پس می توانیم اینگونه بگوییم:
در هر دو کد از لغو روش استفاده شده.
من منظور شما رو از لغو روش نمی فهمم.


در کد اول چند ریختی زمان اجرا را داریم ولی در کد دوم چند ریختی زمان کامپایل(یا کلاً نبود چند ریختی).
در دومی هیچ نوع چند ریختی نداریم. حتی از نوع زمان کامپابلشم نداریم.


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

یکی از کاربرد های کلاس های پایه این هست که برای فرزندان خود واسط (interface) تعریف میکنند. یعنی مثلن یک متدی رو تعریف میکنند تا همه فرزندان رو مجبور کنند که این متد رو داشته باشن! واقعیت هم همین هست! شما کدوم شکل بسته هندسی رو میشناسید که مساحت (area) نداشته باشه؟ پس این متد باید در کلاس پایه باشه چون همه فرزندان باید داشته باشنش! اتفاقن این اجبار کار برنامه نویس رو راحت میکنه. چون اگز اینطور نبود ممکن بود برنامه نویس یادش بره در فرزندی area بزاره اون وقت برنامش به مشکل می خورد...

قله بلند
شنبه 21 آذر 1388, 17:05 عصر
سلام
من این اصطلاح رو از کتاب E-book_JAVA_Lan صفحه 197 گفتم. آدرس این کتاب را در سایت برنامه نویس پیدا کردم. اجازه دهید یک مثال بزنم:
//Method overriding
class A
{
int i,j;
A(int a,int b)
{
i=a;
j=b;
}
void show()
{
System.out.println("i and j= "+i+" "+j);
}
}
class B extends A
{
int k;
B(int a,int b,int c)
{
super(a,b);
k=c;
}
void show()
{
System.out.println("k= "+k);
}
}
public class Override
{
public static void main(String args[])
{
B ob=new B(1,2,3);
ob.show();
}
}
وقتی برنامه اجرا می شود، فقط مقدار k برگردانده می شود و تابع show در کلاس پایه دیگر اجرا نمی شود. به این در این کتاب لغو روش می گویند.
اولاً توضیحاتتان خوب بود و من فهمیدم. تشکر می کنم. و یک خواهش دیگر اینکه در یک کد که از ارث بری استفاده می کند باید چه شرایطی برقرار باشد تا به آن بگویند چند ریختی زمان کامپایل.
با تشکر از همکاری و همراهی شما

cups_of_java
شنبه 21 آذر 1388, 22:25 عصر
وقتی برنامه اجرا می شود، فقط مقدار k برگردانده می شود و تابع show در کلاس پایه دیگر اجرا نمی شود. به این در این کتاب لغو روش می گویند.

این موضوع Overriding هست که براش معادل فارسی خوبی نمی شناسم. کلمه لغو روش رو نمی دونم معادل چه اصطلاحی دونسته اند اما من تا حالا نشنیده بودم و کلمه درستی از نظر علمی هم به نظر نمی رسه و کسی استفاده نمی کنه. به نظرم استنباط نویسنده متن بوده.


در یک کد که از ارث بری استفاده می کند باید چه شرایطی برقرار باشد تا به آن بگویند چند ریختی زمان کامپایل

ببین چند ریختی استاتیک چیزی نیست که به شی گرایی (و ارث بری) ربط داشته باشه. شی گرایی فقط چند ریخنی داینامیک رو براتون فراهم می کنه.

چند ریختی استاتیک به دو روش می تونه مفهوم پیدا کنه و استفاده شه:

1. یکی استفاده از چند ریختی توابع هست که اسمش همون Function Overloading هست.
2. دو استفاده از Generic Programming و یا (template ها در زبان سی پلاس پلاس)

قله بلند
یک شنبه 22 آذر 1388, 14:32 عصر
// Demonstrate method overloading.
class OverloadDemo {
void test() {
System.out.println("No parameters");
}
// Overload test for one integer parameter.
void test(int a) {
System.out.println("a: " + a);
}
// Overload test for two integer parameters.
void test(int a, int b) {
System.out.println("a and b: " + a + " " + b);
}
// overload test for a double parameter
double test(double a) {
System.out.println("double a: " + a);
return a*a;
}
}
class Overload {
public static void main(String args[]) {
OverloadDemo ob = new OverloadDemo();
double result;
// call all versions of test()
ob.test();
ob.test(10);
ob.test(10, 20);
result = ob.test(123.2);
System.out.println("Result of ob.test(123.2): " + result);
}
}

سلام
منظورتان از چند ریختی زمان استاتیک این کد هست؟
کد بالا را از آدرس زیر به دست آوردم:
http://www.java-samples.com/showtutorial.php?tutorialid=284

cups_of_java
یک شنبه 22 آذر 1388, 19:07 عصر
بله، این یکی از مدل هاشه که همون استفاده از سربارگذاری (Overloading) توابع هست.

قله بلند
یک شنبه 22 آذر 1388, 20:22 عصر
با سلام و تشکر فراوان از شما
یک سوال که به نحوی بحث این تاپیک را کامل می کند.
فرض کنید که من کلاس Figure را abstract کنم. پس باید تابع area از این کلاس را نیز abstract کنم. وقتی من با این برنامه، اینگونه برخورد کردم و از روی عمد، تابع area از کلاس R_ectangle را حذف کردم، زمان کامپایل خطا دریافت کردم.
یعنی اینکه در این حالت، باید تمامی کلاس های مشتق شده از کلاس پایه، خودشان area مورد نیازشان را تعریف کنند و دیگر اغماضی برای فراموشی آن وجود ندارد چون دیگر کلاس پایه ای نیست که بتوانند از تابع area آن استفاده کنند.
سوال: آیا این حالت انتزاعی به این خاطر است که تکیه کلاس های فرزند از کلاس پدر به صورت کامل خارج شود و به نوعی اجبار و التزام کامل برای تعریف area ی خود را داشته باشند؟

cups_of_java
دوشنبه 23 آذر 1388, 01:38 صبح
سوال: آیا این حالت انتزاعی به این خاطر است که تکیه کلاس های فرزند از کلاس پدر به صورت کامل خارج شود و به نوعی اجبار و التزام کامل برای تعریف area ی خود را داشته باشند؟

دقیقن. چون کلاس پایه اطلاعاتی برای محاسبه area نداره! نمی دونه مساحت یک شکل رو چطوری حساب کنه! در حقیقت همین یعنی اینکه باید کلاس مجرد Abstract باشه!
این وظیفه اشکال مختلف هست که مشخص کنند area هر کدوم چطوری محاسبه میشه! (یعنی area رو پیاده سازی کنند.)

قله بلند
یک شنبه 29 آذر 1388, 17:36 عصر
سلام
با توجه به برنامه زیر که اجرا شده و نتایج i=5 و j=12 را تولید کرده است، سوالی مطرح است:
class x
{
private int i=19;
public int j=67;
public x(){i=12; System.out.println("i= "+i);}
private void f(){j=i;}
protected void g(){i=36;}
public void h(){f();g();}
}

class y extends x
{
private int i=6;
private void f(){i++;}
protected void g(){i--;}
public void k(){h();System.out.println("i= "+i+"j= "+j);}
}

public class Test
{
public static void main(String args[])
{
y b = new y();
b.k();// result i=5 , j=12
}
}سوال: توابع f() و g() در هر دو کلاس x و y آمده است و چون y از x ارث می برد، پس اجازه اجرای توابع f و g از x سلب می شود.(در صورت ایجاد شیئی از کلاس y). یعنی کلاس y برنده می شود. پس در تابع f، مقدار i=6 و در تابع g، مقدار i=5 می شود. حالا در تابع main، تابع k صدا زده می شود که حاوی تابع h است. این تابع نیز در کلاس x موجود است و حاوی دو تابع f و g می باشد. حالا بین دو کلاس، رقابت چگونه تقسیم می شود؟ overriding چگونه اتفاق می افتد؟ اینطور که به نظر می رسد، تابع f از کلاس x و تابع g از کلاس y پیروز می شوند. چرا؟

cups_of_java
یک شنبه 29 آذر 1388, 19:17 عصر
جملاتتون رو خیلی پیچیده بیان کردید. اصلن نیازی به این همه پیچیدگی نیست! رقابت و برنده و بازنده نداریم!
به یک نکته ظریف توجه نمی کنی شما:
متد f به صورت private تعریف شده. پس این متد فقط مختص خود کلاس هست و اصلن overloading و بحث های مشابه در موردش صادق نیست!
شما اینطور فکر کن: این دو متد f فقط اسمشون یکیه ولی دو تا متد جدا هستند و هیچ ربطی به هم ندارن!

تنها متد g هست که override شده پس کامپایلر میره سراغ پیاده سازی درست! (پس مال y صدا میشه)
در مورد f اصلن overriding صورت نمیگیره پس مستقیمن از x صدا میشه! (می دونید چرا از x و نه y؟)