Konu Tarihi:
Polymorfizm, C++'un erken aşamalarında nesne yönelimli programlamanın ana özelliklerinden biri haline geldi. Amaç, nesnelere temel bir arayüz üzerinden erişebilmek ve belirli bir tür hakkında endişelenmemektir. Bu, kodun ifade yeteneğini ve esnekliğini önemli ölçüde artırır.
Sorun:
Polymorfizm olmadan kod esnek olmaz: nesnelerin türlerini açıkça bilmek, switch/case kullanmak, tür dönüşümlerini manuel olarak yapmak zorundayız. Bu, uygulamanın bakımını ve genişletilebilirliğini karmaşık hale getirir — yeni türler eklemek mevcut kodu değiştirmeden pahalı veya imkansız hale gelir.
Çözüm:
C++'ta polymorfizm, sanal fonksiyonların kullanımıyla elde edilir. Sınıflar sanal yöntemler ilan eder ve miras alan sınıflar bunları uygular. Temel sınıf ortak bir arayüz sağlar ve gerçek eylemler, işaretçi veya referansın işaret ettiği nesnenin gerçek türüne bağlıdır.
Kod örneği:
#include <iostream> class Animal { public: virtual void speak() const { std::cout << "Bazı hayvan sesleri "; } virtual ~Animal() {} }; class Dog : public Animal { public: void speak() const override { std::cout << "Hav hav! "; } }; void makeSound(const Animal& a) { a.speak(); } int main() { Dog dog; makeSound(dog); // Çıktı: Hav hav! }
Anahtar özellikler:
virtual anahtar kelimesi ile ilan edilmelidir.override kullanın — bu kodun güvenliğini artırır.Eğer temel sınıfın yıkıcısını sanal olarak ilan etmezseniz, ne olur?
Temel sınıfın işaretçisi üzerinden bir nesne silindiğinde, yalnızca temel sınıfın yıkıcısı çağrılır, ve türetilmiş sınıfın yıkıcısı çağrılmayacak, bu da kaynak sızıntısına yol açacaktır.
Kod örneği:
class Base { public: ~Base() { /*...*/ } }; class Derived : public Base { public: ~Derived() { /*...*/ } }; Base* obj = new Derived(); delete obj; // UB: Derived::~Derived çağrılmayacak
Sadece kısmen sanal yöntemler ilan edebilir mi, ancak yıkıcıyı sanal bırakabilir miyiz?
Hayır, eğer sınıf polymorfikse (en az bir sanal fonksiyonu varsa), yıkıcı sanal olmalıdır, aksi takdirde bellek veya kaynak sızıntıları kaçınılmazdır.
Sanal fonksiyonlar, static olarak ilan edilen üyeler için çalışır mı?
Hayır, sınıfın statik üyeleri sanal olamaz çünkü belirli bir nesneye ait değillerdir ve onlar için dinamik bağlama mekanizması yoktur.
override metodunun unutulması, bu yanlış bir yeniden tanımlamaya yol açar.Çok büyük bir cihaz sınıfı hiyerarşisi, her türetilmiş sınıf kendi kaynaklarını yönetiyor (örneğin, açık bir dosya), ancak temel sınıfın yıkıcısı sanal değil. Temel bir gösterici üzerinden silme sırasında kaynaklar serbest bırakılmıyor.
Artıları: Proje hızlı bir şekilde inşa ediliyor, minimum sanal çağrı.
Eksileri: Bellek sızıntıları, yanlış imha. Bakımı ve geliştirilmesi son derece zor.
İyi düşünülmüş bir polymorfik hiyerarşi, temel sınıfın sanal fonksiyonları ve sanal yıkıcısı var. override anahtar kelimesi ve RAII ilkeleri kullanılmakta.
Artıları: Kaynaklarla güvenli çalışma, basit genişletme, test edilebilirlik.
Eksileri: Vtable-lookup nedeniyle biraz daha düşük performans, gereksiz yere miras alma durumlarında "over-engineering" aşısı.