D.ershane D Programlama Dili Dersleri

değişmez: [immutable], programın çalışması süresince kesinlikle değişmeyen
referans: [reference], asıl nesneye, onun takma ismi gibi erişim sağlayan program yapısı
sabit: [const], bir bağlamda değiştirilmeyen
sınıf: [class], kendi üzerinde kullanılan işlevleri de tanımlayan veri yapısı
üye işlev: [member function], yapı veya sınıfın kendi tanımladığı işlemleri
yapı: [struct], başka verileri bir araya getiren veri yapısı
... bütün sözlük

Bölümler
İngilizce Kaynaklar
Diğer



const ref Parametreler ve const Üye İşlevler

Bu derste üye işlevlerin const nesnelerle de kullanılabilmeleri için nasıl const olarak işaretlenmeleri gerektiğini göreceğiz. Burada her ne kadar yapıları kullanıyor olsak da; const üye işlevler sınıflar için de geçerlidir.

const nesneler

Şimdiye kadarki derslerde bazı örneklerde const değişkenler ve nesneler tanımlamış ve const anahtar sözcüğünün nesnelerin değiştirilemez olmalarını sağladığını görmüştük:

    const auto okumaSaati = GününSaati(15, 0);

okumaSaati değiştirilemez:

    okumaSaati = GününSaati(16, 0);     // ← derleme HATASI
    okumaSaati.dakika += 10;            // ← derleme HATASI

Derleyici; const nesneye yeni bir değer atanmasına, bir üyesinin değiştirilmesine, veya herhangi başka bir değişiklik yapılmasına izin vermez. Zaten const olarak işaretlemenin amacı da budur: bazı nesnelerin değerlerinin değişmeyeceği garantisi gerekebilir.

const ref parametreler

const ve immutable dersinde gördüğümüz gibi, immutable nesneler programda kesinlikle değişmeyen nesnelerdir. const nesneler ise belirli bir referans yoluyla, veya belirli bir bağlamda değişmeyen nesnelerdir.

Kendisi aslında const olmayan bir nesne, belirli bir bağlamda değiştirilmeden kullanılabilir. Bunun bir örneği, parametrelerdir. const ref olarak işaretlenen bir parametre, o işlev içinde değiştirilmeyecek demektir:

int toplamSaniye(const ref Süre süre)
{
    return 60 * süre.dakika;
}

O işlev, parametresini const olarak işaretleyerek o parametrede değişiklik yapmayacağı garantisini vermiş olur. Derleyici de o nesnenin değiştirilmesine izin vermez:

int toplamSaniye(const ref Süre süre)
{
    süre.dakika = 7;       // ← derleme HATASI
// ...
}
const olmayan ref parametreler

ref parametrelerin işlev içinde değiştirilmemeleri yönünde bir kısıtlama yoktur. O parametreyi değiştirmiyor bile olsalar, bunun garantisini vermedikleri için o işlevlere const nesne gönderilemez:

// süre'yi değiştirmiyor olsa bile const olarak işaretlememiş
int toplamSaniye(ref Süre süre)
{
    return 60 * süre.dakika;
}
// ...
    const Süre ısınmaSüresi = Süre(3);
    toplamSaniye(ısınmaSüresi);          // ← derleme HATASI

Not: Yukarıdaki kod, bu dersi yazdığım sırada kullandığım derleyicinin (dmd 2.046) bir hatası yüzünden derlenebiliyor. O hata giderildiğinde yukarıdaki kod derleme hatasına neden olacaktır.

Derleyici, const olan ısınmaSüresi nesnesinin toplamSaniye işlevine gönderilmesine izin vermez; çünkü toplamSaniye işlevi, parametresinde değişiklik yapmayacağı garantisini vermemektedir.

const olmayan üye işlevler

Nesneleri değiştirmenin başka bir yolu, üye işlevlerdir. Örneğin GününSaati.ekle işlevi, üzerinde çağrıldığı nesneyi ona bir Süre ekleyerek değiştiriyordu:

struct GününSaati
{
// ...
    void ekle(in Süre süre)
    {
        dakika += süre.dakika;

        saat += dakika / 60;
        dakika %= 60;
        saat %= 24;
    }
// ...
}
// ...
    auto başlangıç = GününSaati(5, 30);
    başlangıç.ekle(Süre(30));          // başlangıç değişir
const üye işlevler

Bazı üye işlevler, üzerinde çağrıldıkları nesnede değişiklik yapmazlar:

struct GününSaati
{
// ...
    string toString()
    {
        return format("%02s:%02s", saat, dakika);
    }
// ...
}

toString'in işi, nesneyi string olarak ifade etmektir; nesnenin kendisinde bir değişiklik yapmaz.

Üye işlevlerin nesnede bir değişiklik yapmayacakları garantisi, parametre listesinden sonra yazılan const sözcüğü ile belirtilir:

struct GününSaati
{
// ...
    string toString() const
    {
        return format("%02s:%02s", saat, dakika);
    }
}

O const, nesnenin o işlev içinde değiştirilmeyeceği garantisini sağlar.

Böylece derleyici toString'i const nesnelerle de çağırabilir. Çünkü toString const olarak işaretlenmemiş olsa, const nesneleri yazdıramamak gibi yapay bir kısıtlamayla karşı karşıya kalınır:

struct GününSaati
{
// ...
    // const olarak işaretlenmemiş (yanlış tasarım)
    string toString()
    {
        return format("%02s:%02s", saat, dakika);
    }
}
// ...
    const auto başlangıç = GününSaati(5, 30);
    string dizgiOlarak = başlangıç.toString(); // ← derleme HATASI

Şimdiye kadarki derslerde gördüğümüz toString üye işlevlerinin bu kısıtlama yüzünden yanlış tasarlandıklarını söyleyebiliriz.

Ne zaman kullanmalı

toString gibi, nesnede değişiklik yapmayan üye işlevleri her zaman için const olarak işaretleyin:

struct GününSaati
{
// ...
    string toString() const
    {
        return format("%02s:%02s", saat, dakika);
    }
}

Böylece yapının ve sınıfın kullanışlılığı gereksizce kısıtlanmamış olur. Bundan sonraki derslerdeki kodlar da buna uygun olarak tasarlanacaklar.

Not: İşlevin nesnede değişiklik yapmayacağını garanti eden bu const anahtar sözcüğü aslında işlevin tanımından önce de yazılabilir:

    // üsttekiyle aynı şey
    const string toString()
    {
        return format("%02s:%02s", saat, dakika);
    }

Dönüş türüyle karışma riski olduğu için ben const anahtar sözcüğünü bu şekilde değil, yukarıda gösterdiğim gibi parametre listesinden sonra yazmayı yeğliyorum.