Giriş: Tamamlanmamış Planlar ve Ortak Temeller

Nesne Yönelimli Programlamada sınıflar, nesnelerin planlarıdır. Bazen, bir planın bazı kısımları tüm alt türler için ortak ve belliyken (somut), bazı kısımlarının ise her alt tür tarafından kendi özel şekliyle doldurulması gereken boşluklar veya talimatlar şeklinde olmasını isteriz. Yani, tek başına tam olarak “anlamlı” veya “kullanılabilir” olmayan, ancak kendisinden türeyecek sınıflar için ortak bir yapı ve zorunlu davranışlar tanımlayan bir temel plana ihtiyaç duyarız.

İşte Soyut Sınıflar (Abstract Classes) bu ihtiyacı karşılar. Soyut bir sınıf, doğrudan örneklenemeyen (yani new SoyutSinif() yapılamayan), ancak diğer sınıfların miras alması (inherit) için tasarlanmış bir temel sınıftır. Amacı, bir grup ilişkili sınıf için ortak bir arayüz (interface gibi) ve/veya ortak bir uygulama (implementation) sağlamaktır.

Soyut Sınıfların Temel Amaçları:

Ortak Temel Oluşturma: Birbirine benzeyen, “bir türüdür” (is-a) ilişkisi içinde olan sınıflar için ortak özellikleri (alanlar, özellikler) ve ortak davranışları (somut metotlar) tek bir yerde tanımlamak. Bu, kod tekrarını önler.
Soyutlama (Abstraction): Alt sınıfların uygulamak zorunda olduğu belirli metotları (soyut metotlar) tanımlayarak bir sözleşme sunmak, ancak bu metotların nasıl uygulanacağı detayını alt sınıflara bırakmak.
Varsayılan Davranış Sağlama: Bazı metotlar için varsayılan (somut) bir uygulama sunarken, alt sınıfların isterlerse bu davranışı değiştirmelerine (override etmelerine) izin vermek (sanal metotlar — virtual methods).
Kalıtım Hiyerarşisi Kurma: Belirli bir kavramsal hiyerarşinin temelini oluşturmak (örn. Sekil soyut sınıfından türeyen Daire, Kare, Ucgen somut sınıfları).
Soyut sınıflar, hem “ne yapılacağını” (soyut üyelerle) hem de kısmen “nasıl yapılacağını” (somut üyelerle) tanımlayabilme esnekliği sunar.

Bölüm 1: Soyut Sınıf Tanımlama (abstract Anahtar Kelimesi)

Bir sınıfı soyut olarak işaretlemek için sınıf tanımının başına abstract anahtar kelimesi eklenir.

Sözdizimi:

[erişim_belirleyici] abstract class SoyutSinifAdi
{
// Üyeler:
// - Somut Alanlar (Fields)
// - Somut veya Soyut Özellikler (Properties)
// - Somut, Soyut (Abstract) veya Sanal (Virtual) Metotlar
// - Yapıcılar (Constructors)
// - Olaylar (Events)
// - İndeksleyiciler (Indexers)
// ... vb.
}
abstract: Sınıfın soyut olduğunu ve doğrudan örneklenemeyeceğini belirtir (new SoyutSinifAdi() yapılamaz).
Erişim Belirleyiciler: Normal sınıflar gibi public, internal vb. olabilir.
Üyeler: Soyut sınıflar, normal (somut) sınıflar gibi çeşitli üyeler içerebilir:
Alanlar (Fields): Normal alanlar tanımlanabilir.
Özellikler (Properties): Hem somut (gövdeli get/set) hem de soyut (gövdesiz get/set imzaları) özellikler tanımlanabilir.
Metotlar (Methods):
Somut Metotlar: Gövdesi olan normal metotlar. Bunlar alt sınıflara doğrudan miras kalır ve ortak işlevsellik sağlar.
Soyut Metotlar (abstract): Sadece imzası tanımlanır, gövdesi olmaz ve abstract anahtar kelimesiyle işaretlenir. Soyut metotlar örtük olarak sanaldır (virtual). Soyut bir sınıfı miras alan somut (soyut olmayan) alt sınıflar, miras aldıkları tüm soyut metotları override anahtar kelimesiyle uygulamak zorundadır.
Sanal Metotlar (virtual): Gövdesi olan metotlardır, ancak virtual anahtar kelimesiyle işaretlenerek alt sınıfların bu metodu isteğe bağlı olarak geçersiz kılmasına (override) izin verilir. Alt sınıf geçersiz kılmazsa, üst sınıftaki varsayılan uygulama kullanılır.
Yapıcılar (Constructors): Soyut sınıfların yapıcıları olabilir. Bunlar doğrudan new ile çağrılamasa da, alt sınıf yapıcıları tarafından base(…) anahtar kelimesiyle çağrılarak üst sınıfın başlatılmasını sağlarlar.
Önemli Kurallar:

Bir sınıf içinde en az bir tane abstract üye (metot veya özellik) varsa, o sınıfın kendisi de abstract olarak işaretlenmek zorundadır.
Soyut üyelerin (metot, özellik, olay, indeksleyici) uygulama gövdesi olmaz ve private olamazlar (çünkü alt sınıflar tarafından uygulanmaları gerekir).
Soyut sınıflar sealed (miras alınamaz) olamazlar, çünkü temel amaçları miras alınmaktır.
Soyut sınıflar static olamazlar.
Örnek Soyut Sınıf:

using System;
public abstract class Sekil // Soyut sınıf - doğrudan örneği oluşturulamaz
{
// Somut Özellik (tüm şekillerin bir rengi olabilir)
public string Renk { get; set; }
// Yapıcı (alt sınıflar tarafından base() ile çağrılabilir)
public Sekil(string renk)
{
Console.WriteLine("Sekil yapıcısı çalıştı.");
this.Renk = renk;
}
// Soyut Özellik (her şeklin alanı farklı hesaplanır, uygulama zorunlu)
public abstract double Alan { get; } // Sadece get'i soyut olabilir
// Soyut Metot (her şekil farklı çizilir, uygulama zorunlu)
public abstract void Ciz();
// Sanal Metot (varsayılan bir davranış var, alt sınıflar isterse değiştirebilir)
public virtual void BilgiGoster()
{
Console.WriteLine($"Bu bir {Renk} şekildir.");
Console.WriteLine($"Alanı: {this.Alan:F2}"); // Soyut özelliğe erişim (alt sınıf uygulamasından gelecek)
}
// Somut Metot (tüm şekiller için ortak)
public void RengiDegistir(string yeniRenk)
{
this.Renk = yeniRenk;
Console.WriteLine($"Şeklin rengi {yeniRenk} olarak değişti.");
}
}
Bölüm 2: Soyut Sınıftan Miras Alma ve Uygulama

Soyut bir sınıftan miras almak, normal sınıf kalıtımı gibi : operatörü ile yapılır. Ancak önemli bir fark vardır: Soyut sınıfı miras alan somut ( abstract olmayan) bir alt sınıf, üst sınıftaki tüm abstract üyeleri (abstract metotlar ve özellikler) override anahtar kelimesiyle uygulamak (gerçekleştirmek) zorundadır.

Sözdizimi:

class AltSinif : SoyutUstSinif
{
// Üst sınıftaki abstract üyelerin override ile uygulanması ZORUNLUDUR.
public override DonusTuru SoyutMetotAdi(parametreler)
{
// Metot gövdesi - Uygulama burada yapılır
}
public override OzellikTuru SoyutOzellikAdi
{
get { /* get uygulaması / }
// set { /
set uygulaması (eğer abstract set varsa) */ }
}
// İsteğe bağlı olarak virtual metotlar da override edilebilir.
public override void SanalMetotAdi()
{
// base.SanalMetotAdi(); // İsteğe bağlı: Üst sınıfın metodunu çağır
// Yeni veya ek davranışlar
}
// Alt sınıfa özgü üyeler
// ...
}
Örnek (Soyut Sekil Sınıfından Türetme):

// Daire Sınıfı
public class Daire : Sekil // Sekil'den miras alıyor
{
public double Yaricap { get; set; }
// Üst sınıf yapıcısını çağırma (base)
public Daire(string renk, double yaricap) : base(renk)
{
Console.WriteLine("Daire yapıcısı çalıştı.");
this.Yaricap = yaricap;
}
// Soyut Alan özelliğini UYGULAMA (override ZORUNLU)
public override double Alan => Math.PI * Yaricap * Yaricap;
// Soyut Ciz metodunu UYGULAMA (override ZORUNLU)
public override void Ciz()
{
Console.WriteLine($"{Renk} renkte, {Yaricap} yarıçaplı bir daire çiziliyor...");
}
// Sanal BilgiGoster metodunu GEÇERSİZ KILMA (override OPSİYONEL)
public override void BilgiGoster()
{
// base.BilgiGoster(); // İstersek üst sınıfınkini çağırabiliriz
Console.WriteLine($"--- Daire Bilgisi ---");
Console.WriteLine($"Renk: {Renk}, Yarıçap: {Yaricap}");
Console.WriteLine($"Alan: {this.Alan:F2}"); // Kendi Alan özelliğini kullanır
Console.WriteLine($"---------------------");
}
}
// Dikdörtgen Sınıfı
public class Dikdortgen : Sekil
{
public double Genislik { get; set; }
public double Yukseklik { get; set; }
public Dikdortgen(string renk, double genislik, double yukseklik) : base(renk)
{
Console.WriteLine("Dikdörtgen yapıcısı çalıştı.");
this.Genislik = genislik;
this.Yukseklik = yukseklik;
}
// Soyut Alan özelliğini UYGULAMA
public override double Alan => Genislik * Yukseklik;
// Soyut Ciz metodunu UYGULAMA
public override void Ciz()
{
Console.WriteLine($"{Renk} renkte, {Genislik}x{Yukseklik} boyutlarında bir dikdörtgen çiziliyor...");
}
// BilgiGoster metodunu override ETMİYORUZ, Sekil'deki varsayılan kullanılacak.
}
// Kullanım
public class SoyutKullanim
{
public static void Main(string[] args)
{
// Sekil s = new Sekil("Mavi"); // Hata! Soyut sınıf örneği oluşturulamaz.
Daire daire1 = new Daire("Kırmızı", 5.0);
Dikdortgen dikdortgen1 = new Dikdortgen("Mavi", 4.0, 6.0);
daire1.Ciz(); // Kırmızı renkte, 5 yarıçaplı bir daire çiziliyor...
dikdortgen1.Ciz(); // Mavi renkte, 4x6 boyutlarında bir dikdörtgen çiziliyor...
daire1.BilgiGoster(); // Daire'nin override ettiği metot çalışır
dikdortgen1.BilgiGoster(); // Sekil'deki virtual metot çalışır (Alan hesaplanır)
daire1.RengiDegistir("Yeşil"); // Sekil'den miras alınan somut metot
Console.WriteLine("\nPolimorfizm Örneği:");
// Soyut sınıf referansı, türetilmiş sınıf nesnelerini tutabilir
List sekiller = new List();
sekiller.Add(daire1);
sekiller.Add(dikdortgen1);
sekiller.Add(new Daire("Sarı", 2.0));
foreach (Sekil s in sekiller)
{
// Çalışma zamanında nesnenin gerçek türüne göre uygun metot çağrılır (polimorfizm)
s.BilgiGoster();
s.Ciz();
Console.WriteLine("---");
}
}
}
Bölüm 3: Soyut Üyeler (abstract) vs. Sanal Üyeler (virtual)

Soyut sınıflar hem abstract hem de virtual üyeler içerebilir. Aralarındaki fark önemlidir:

Soyut Üyeler (abstract Metot/Özellik):
Gövdesi yoktur. Sadece imzası tanımlanır.
Tanımlandığı sınıf abstract olmak zorundadır.
Miras alan somut alt sınıflar tarafından override edilmesi zorunludur.
Amacı: Alt sınıfların mutlaka sağlaması gereken bir davranışı veya özelliği tanımlamak, ancak uygulamasını alt sınıfa bırakmaktır. Bir sözleşmenin parçasıdır.
Örtük olarak sanaldırlar (yani virtual yazmaya gerek yoktur, zaten override edilebilirler).
Sanal Üyeler (virtual Metot/Özellik):
Gövdesi (uygulaması) vardır. Varsayılan bir davranış sağlarlar.
Tanımlandığı sınıf abstract olmak zorunda değildir (normal sınıflarda da olabilir).
Miras alan alt sınıflar tarafından override edilmesi opsiyoneldir. Alt sınıf isterse kendi uygulamasını yazarak varsayılan davranışı geçersiz kılabilir, istemezse üst sınıftaki uygulama miras kalır.
Amacı: Varsayılan bir davranış sunmak ama alt sınıflara bu davranışı özelleştirme veya genişletme imkanı tanımaktır.
Özetle:

abstract: “Bunu yapmak zorundasın, ama nasıl yapacağın sana kalmış.” (Uygulama yok, override zorunlu)
virtual: “Ben bunu böyle yapıyorum, istersen sen farklı yapabilirsin (override edebilirsin), istemezsen benim yaptığımı kullanırsın.” (Uygulama var, override opsiyonel)
Bölüm 4: Soyut Sınıflar vs. Arabirimler (Interfaces)

Hem soyut sınıflar hem de arabirimler soyutlama sağlamak için kullanılır ve benzerlikleri vardır (örneğin ikisi de doğrudan örneklenemez). Ancak önemli farkları ve farklı kullanım amaçları bulunur:

ÖzellikSoyut Sınıf (abstract class)Arabirim (interface)Temel AmaçOrtak temel sınıf, “bir türüdür” (is-a) ilişkisi, varsayılan davranışSözleşme, yetenek (“yapabilir” — can-do) ilişkisiKalıtımBir sınıf sadece bir soyut sınıfı miras alabilirBir sınıf birden fazla arabirimi uygulayabilirÜyelerSoyut, sanal ve somut üyeler (metot, özellik), alanlar, yapıcılar içerebilirGenellikle gövdesiz üyeler (C# 8+ default/static olabilir), alan ve yapıcı içeremezUygulamaSoyut üyeler alt sınıfta override edilmeli, somut/sanal üyeler miras alınırTüm üyeler (default olmayanlar) uygulayan sınıfta gerçekleştirilmeliErişim BelirleyicilerÜyeler farklı erişim belirleyicilere sahip olabilir (public, protected vb.)Üyeler varsayılan olarak public’tir (ve değiştirilemezdi — C# 8+ ile farklılıklar var)Durum (State)Alanlar (fields) aracılığıyla durum saklayabilirDurum saklayamaz (alanları yoktur)Ne Zaman Kullanılır?Yakından ilişkili sınıflar için ortak kod ve temel yapı sağlamak. Kalıtım hiyerarşisinin kökünde.Farklı sınıflara ortak yetenek/sözleşme eklemek. Çoklu “kalıtım” ihtiyacı. Gevşek bağlılık.

Basit bir kural:

Eğer bir “bir türüdür” (is-a) ilişkisi tanımlıyorsanız ve alt sınıflar arasında önemli miktarda ortak kod (uygulama) paylaşımı olacaksa, soyut sınıf daha uygun olabilir (örn. Sekil -> Daire, Kare).
Eğer farklı türdeki sınıfların sahip olabileceği bir “yetenek” veya “sözleşme” tanımlıyorsanız (örn. IUcabilir, ILogger, IDisposable), arabirim daha uygun bir seçimdir.
Bazen bir sınıf hem bir soyut sınıftan miras alıp hem de bir veya daha fazla arabirimi uygulayabilir.

Bölüm 5: Pratik Kullanım Senaryoları

Grafik Kütüphaneleri: Sekil soyut sınıfı, tüm şekillerin ortak özelliklerini (Renk, Konum) ve soyut AlanHesapla(), Ciz() metotlarını tanımlayabilir. Daire, Dikdortgen gibi somut sınıflar Sekil’den türeyerek bu metotları uygular.
Veritabanı Erişim Katmanları: VeritabaniBaglantisi soyut sınıfı, tüm veritabanı bağlantıları için ortak Baglan(), BaglantiyiKapat() gibi somut veya sanal metotlar ve belirli veritabanı türüne (SQL Server, Oracle) özgü işlemleri (örn. SorguCalistir) soyut metot olarak tanımlayabilir. SqlServerBaglantisi, OracleBaglantisi gibi sınıflar bu soyut metotları uygular.
Oyun Geliştirme: Karakter soyut sınıfı, Oyuncu, Dusman gibi alt sınıflar için ortak özellikleri (Can, Pozisyon) ve metotları (HareketEt — virtual, Saldir — abstract) tanımlayabilir.
Framework ve Kütüphane Tasarımı: Framework geliştiricileri, kullanıcıların kendi özel uygulamalarını oluşturmaları için genişletilebilir bir temel sağlamak amacıyla soyut sınıfları sıklıkla kullanır. Kullanıcı, soyut sınıfı miras alır ve soyut metotları doldurarak framework’ün beklediği işlevselliği sağlar.
Bölüm 6: Sonuç — Soyutlama ve Genişletilebilirliğin Temeli

Soyut Sınıflar (abstract class), C#’ta güçlü bir soyutlama ve kod yeniden kullanımı aracıdır. Doğrudan örneklenemeyen bu sınıflar, bir kalıtım hiyerarşisi için ortak bir temel oluşturarak, ilgili sınıflar arasında hem ortak davranışları (somut/sanal üyelerle) hem de zorunlu kılınan farklı uygulamaları (soyut üyelerle) tanımlamamızı sağlar.

Soyut üyeler (abstract), alt sınıfların belirli bir sözleşmeye uymasını garanti ederken, sanal üyeler (virtual) varsayılan bir davranış sunup gerektiğinde özelleştirmeye olanak tanır. Soyut sınıflar, alanlar ve yapıcılar içerebilmeleriyle arabirimlerden ayrılırlar ve genellikle daha güçlü bir “bir türüdür” (is-a) ilişkisini modellemek için kullanılırlar.

Bir sınıfın sadece bir soyut sınıftan miras alabilmesi (tekli kalıtım), tasarım kararlarını etkileyen önemli bir faktördür. Ortak yetenekler için arabirimler, ortak temel ve uygulama için soyut sınıflar tercih edilir.

Soyut sınıfları ve soyut/sanal üyeleri doğru bir şekilde anlamak ve kullanmak, C#’ta esnek, genişletilebilir, bakımı kolay ve iyi tasarlanmış nesne yönelimli sistemler oluşturmanın temelini oluşturur. Bu kavramlar, OOP’nin soyutlama ve polimorfizm gibi temel prensiplerini hayata geçirmemize yardımcı olur.

Abdulkadir Güngör - Kişisel WebSite
Abdulkadir Güngör - Kişisel WebSite
Abdulkadir Güngör - Özgeçmiş
Github
Github
Linkedin