C#’ta Virtual, Override ve Abstract Methodlar

C#’ta bir method örneği, virtual anahtar sözcüğü ile tanımlanırsa, o methoda virtual (sanal) method adı verilir.

Bir sanal method, ana sınıf tipinden ziyade, güncel atanmış tip ile ilişkilendirilmiş methodu kullanmanıza izin verir.

Bir sanal method türetilmiş sınıfı tarafından etkisiz hale getirilebilir. Bir method örneğinde override anahtar sözcüğü varsa, o method, kalıtım alınmış sanal methodu aynı method imzası ile geçersiz kılar. Bu tür bir sanal method eğer overload olmuşsa, tanımlanmış değişkenin data tipinden ziyade verinin gerçek sınıf tipi runtime zamanında kullanılır. Bunun anlamı; temel sınıf bir çok türetilmiş sınıf tarafından kullanılabilir.

Önemli: Buradaki ince bir nokta, override edilmiş bir sanal method, hala o sınıfın bir methodu olarak hesab katılır. Türetilmiş sınıf, sanal sınıf override edildiği zaman onu göstermek zorundadır. Bu override anahtar sözcüğünü yeni method oluşumunda kullanılarak gösterilir.

Bir abstract (soyut) method, uygulanmayan bir sanal methodtur. Bu methodlar, abstract anahtar sözcüğü ile tanımlanır ve sadece astract olarak tanımlanmış sınıflara izin verilir. Bir soyut sınıf, soyut olmayan türetilmiş tüm sınıflar tarafından override edilmelidir.

Aşağıdaki örnekte; soyut sınıf olarak tanımlanmış Deyim sınıfı, ki bir deyim ifade ağacı düğümü temsil eder, 3 tane de türetilmiş sınıf, Sabit, DegiskenReferansi ve İslem, ki bunlar da sabitlerin, değişken referanslarının ve aritmetik işlemlerin deyim ifade ağaçlarını uygularlar.


using System;
using System.Collections;
using System.Linq;
using System.Text;

namespace HelloWorld
{
public abstract class Deyim
{
public abstract double Hesapla(Hashtable vars);
}
public class Sabit : Deyim
{
double value;
public Sabit(double value)
{
this.value = value;
}
public override double Hesapla(Hashtable vars)
{
return value;
}
}
public class DegiskenReferansi : Deyim
{
string name;
public DegiskenReferansi(string name)
{
this.name = name;
}
public override double Hesapla(Hashtable vars)
{
object value = vars[name];
if (value == null)
{
throw new Exception("Bilinmeyen deşiken " + name);
}
return Convert.ToDouble(value);
}
}
public class İslem : Deyim
{
Deyim sol;
char op;
Deyim sag;

public İslem(Deyim sol, char op, Deyim sag)
{
this.sol = sol;
this.op = op;
this.sag = sag;
}

public override double Hesapla(Hashtable vars)
{
double x = sol.Hesapla(vars);
double y = sag.Hesapla(vars);
switch (op)
{
case '+': return x + y;
case '-': return x - y;
case '*': return x * y;
case '/': return x / y;
}
throw new Exception("Bilinmeyen operatör");
}
}
} 

Bu 4 sınıf, modern matematik işlemler için kullanılabilir. Örneğin, bu sınıf örneklerini kullanarak x + 7 deyimi şu şekilde gösterilebilir;


static void Main()
{
Deyim d = new İslem(new DegiskenReferansi("x"), '+', new Sabit(7));
} 

Burada Deyim sınıfının Hesapla methodu verilen değeri hesaplamak ve bir dobule değeri üretmek görevindedir. Bu method Hashtable adında değişken isimlerini ve değerlerini içeren bir parametre alır. Hesapla methodu, sanal soyut bir method olduğundan, bunun anlamı; soyut olmayan türetilmiş sınıflar güncel bir uygulama sağlamak için bu methodu override etmek zorundalar.

Sabit sınıfının Hesapla implementasyonu, basit olarak geriye depolanmış bir sabit (constant) döndürür. DegiskenReferansi implementasyonu, Hashtable içerisindeki değişken ismine bakar ve sonuçlanan değeri geri döndürür. İslem implementasyonun görevi, öncelikle sol ve sağ operandlarını (Recursif olarak çağırılan Hesapla() methodları ile) hesaplayarak, verilen aritmetik işlemi gerçekleştirmektir.

Aşağıdaki program Deyim sınıfını kullanarak x * (y + 3) işlemini farklı değerler kullanarak hesaplar;


static void Main()
{
Deyim d = new İslem(new DegiskenReferansi("x"), '*', new İslem(new DegiskenReferansi("y"), '+', new Sabit(3)));

Hashtable vars = new Hashtable();

vars["x"] = 2;
vars["y"] = 5;
Console.WriteLine(d.Hesapla(vars)); // Çıktı 16 olur.

vars["x"] = 3;
vars["y"] = 7;
Console.WriteLine(d.Hesapla(vars)); // Çıktı 30 olur.
}