Sanal Metotları Uygulamak [13]

Sanal metotların gücünü daha iyi kavramak için bu metotları TwoDShape sınıfına uygulayacağız. önceki örneklerde, TwoDShape'ten türetilen her sınıf, area() adında bir metot tanımlamaktaydı. Bu kullanım bize bir fikir verir: area()'yı TwoDShape sınıfının bir sanal metodu yapmak çok daha iyi olabilir. Bu sayede, türetilmiş sınıfların her biri area()'yı devre dışı bırakabilir ve sınıf içinde belirtilen şeklin alanının nasıl hesaplandığını da tanımlayabilir. Aşağıdaki program bunu gerçekleştirir. Kolaylık sağlamak için TwoDShape'e ayrıca bir de isim özelliği eklenmektedir. (Bu, sınıfları göstermeyi kolaylaştırır.)

// sanal metotlar ve cokbicimlilik kullanilir.
using System;

class TwoDShape {
double pri_width; // private
double pri_height; // private
string pri_name; // private
//varsayilan yapilandirici.
public TwoDShape() {
width=height=0.0;
name="null";
}
// parametreli yapilandirici
public TwoDShape(double w, double h, string n) {
width=w;
height=h;
name=n;
}
//esit width ve height degerine sahip bir nesne yapilandir.
public TwoDShape(double x, string n) {
width=height=x;
name=n;
}
//bir nesneden bir baska nesne yapilandir.
public TwoDShape(TwoDShape ob) {
width=ob.width;
height=ob.height;
name=ob.name;
}
//width, height ve name icin ozellikler
public double width {
get { return pri_width; }
set { pri_width=value; }
}
public double height {
get { return pri_height; }
set { pri_height=value; }
}
public string name {
get { return pri_name; }
set { pri_name=value; }
}
public void showDim() {
Console.WriteLine("width and height are " + width + " and " + height);
}
public virtual double area() {
Console.WriteLine("area() must be overriden");
return 0.0;
}
}

// Ucgenler icin TwoDShape'ten turetilen bir sinif.
class Triangle : TwoDShape {
string style; // ozel
// varsayilan yapilandirici
public Triangle() {
style="null";
}
// Triangle icin yapilandirici.
public Triangle(string s, double w, double h) : base (w, h, "triangle") {
style=s;
}
// ikizkenar bir ucgen yapilandir.
public Triangle(double x) : base(x, "triangle") {
style="isosceles";
}
//bir nesneden baska bir nesne yapilandir.
public Triangle(Triangle ob) : base(ob) {
style=ob.style;
}
//Triangle icin area()'yı devre disi birak.
public override double area() {
return width*height/2;
}
// ucgenin seklini goster.
public void showStyle() {
Console.WriteLine("Triangle is " + style);
}
}

//dikdortgenler icin TwoDShape'ten turetilmis bir sinif.
class Rectangle : TwoDShape {
//Rectangle icin yapilandirici
public Rectangle(double w, double h) : base(w, h, "rectangle"){
}
//bir kare yapilandir.
public Rectangle(double x) : base(x, "rectangle") {
}
//bir nesneden bir baska nesne yapilandir.
public Rectangle(Rectangle ob) : base(ob) {
}
//dikdortgen bir kareyse true dondur.
public bool isSquare() {
if(width==height) return true;
return false;
}
//Rectangle icin area()'yi devre disi birak.
public override double area() {
return width*height;
}
}

class DynShapes {
public static void Main() {
TwoDShape[] shapes=new TwoDShape[5];
shapes[0]=new Triangle("right", 8.0, 12.0);
shapes[1]=new Rectangle(10);
shapes[2]=new Rectangle(10, 4);
shapes[3]=new Triangle(7.0);
shapes[4]=new TwoDShape(10, 20, "generic");
for (int i=0; i<5; i++) {
Console.WriteLine("object is " + shapes[i].name);
Console.WriteLine("Area is " + shapes[i].area());
Console.WriteLine();
}
}
}

Programin çıktısı:

object is triangle
Area is 48

object is rectangle
Area is 100

object is triangle
Area is 40

object is triangle
Area is 24,5

object is generic
area() must be overriden
Area is 0

Programı yakından inceleyelim. Öncelikle, daha önce açıklandığı gibi, area() metodu TwoDShape içinde virtual olarak deklare edilir ve Rectangle tarafından devre dışı bırakılır. TwoDShape içinde area(), kullanıcıya bu metodun bir türetilmiş sınıf tarafından devre dışı bırakılması gerektiği bilgisini veren bir yer tutucu görevini görür. area()'nın her devre dışı bırakılışında türetilmiş sınıf içine paketlenmiş nesnenin tipine uygun bir uygulama gerçekleştirilir. Yani, örneğin bir elips sınıfını uygluyor olsaydınız, area() lipsin alanını hesaplamak durumunda olurdu.
Yukarıdaki bir baska önemli özellik daha mevcuttur. Dikkat ederseniz, Main() içinde shapes, TwoDShape nesnelerinden oluşan bir dizi olarak deklare edilir. Ancak, bu dizinin elemanlarına Triangle, Rectangle ve TwoDShape referansları atanır. Bu geçerli bir kullanımdır, çünkü bir temel sınıf referansı bir türetilmiş sınıf nesnesine referansta bulunabilir. Program daha sonra dizi üzerinde ilerler ve nesnelerin her biriyle ilgili bilgileri ekranda gösterir. Oldukça basit olmasına karşın bu program, hem kalıtımın, hem de metotları devre dışı bırakma özelliğinin gücünü ortaya koyar. Temel sınıf referans değişkeninde saklanan nesnenin tipi, programın çalışması sırasında belirlenir ve buna göre hareket edilir.
Eğer TwoDShape'ten bir nesne türetilmişse, bu nesnenin alanı area() çağrılarak elde edilebilir. Ne tür bir şekil kullanılırsa kullanılsın bu işlemn arayüzü aynıdır.

Kaynak: Herbert Schildt
Herkes için C#

Hiç yorum yok:

Yorum Gönder