Bu cevaplarla varsayımlara giriyorsunuz, bu yüzden netlik uğruna daha basit, daha aşağıya doğru bir açıklama yapmaya çalışacağım.
Nesneye yönelik tasarımın temel ilişkileri ikidir: IS-A ve HAS-A. Ben uydurmadım. Buna böyle denir.
IS-A, belirli bir nesnenin, sınıf hiyerarşisinde üstünde olan sınıfın varlığını tanımladığını belirtir. Muz nesnesi, meyve sınıfının bir alt sınıfı ise bir meyve nesnesidir. Bu, bir meyve sınıfının kullanılabileceği her yerde, bir muzun kullanılabileceği anlamına gelir. Yine de refleksif değildir. Belirli bir sınıf çağrılırsa, belirli bir sınıfın temel sınıfını değiştiremezsiniz.
Has-a, bir nesnenin bileşik sınıfın bir parçası olduğunu ve bir mülkiyet ilişkisi olduğunu belirtir. C ++ 'da üye bir nesne olduğu anlamına gelir ve bu nedenle onus, kendini yok etmeden önce onu atmak veya sahipliğini elden çıkarmak için kendi sınıfındadır.
Bu iki kavramın tek miras dillerinde gerçekleştirilmesi, c ++ gibi bir çoklu miras modelinden daha kolaydır, ancak kurallar esasen aynıdır. Karmaşıklık, bir Banana sınıfı işaretçisini Fruit sınıfı işaretçisini alan bir işleve geçirmek gibi, sınıf kimliği belirsiz olduğunda ortaya çıkar.
Sanal işlevler, öncelikle, bir çalışma zamanı şeyidir. Çalışan programda çağrıldığı sırada hangi işlevin çalıştırılacağına karar verilmesi için polimorfizmin bir parçasıdır.
Sanal anahtar sözcük, sınıf kimliği hakkında belirsizlik varsa işlevleri belirli bir sırada bağlamak için bir derleyici yönergesidir. Sanal işlevler her zaman üst sınıflardadır (bildiğim kadarıyla) ve derleyiciye üye işlevlerinin adlarına bağlanmasının önce alt sınıf işlevi ve daha sonra üst sınıf işlevi ile gerçekleşmesi gerektiğini belirtir.
Fruit sınıfı, varsayılan olarak "NONE" döndüren bir sanal işlev rengine () sahip olabilir. Banana sınıfı color () işlevi "SARI" veya "KAHVERENGİ" döndürür.
Ama bir Meyve işaretçisini alan işlev, kendisine gönderilen Banana sınıfında color () öğesini çağırırsa - hangi color () işlevi çağrılır? İşlev normalde bir Fruit nesnesi için Fruit :: color () yöntemini çağırır.
Bu zamanın% 99'u amaçlanan şey değildir. Ancak Fruit :: color () sanal olarak bildirildiyse, nesne için Banana: color () çağrılır çünkü çağrı sırasında doğru color () işlevi Fruit pointer'a bağlanır. Çalışma zamanı, Fruit sınıfı tanımında sanal olarak işaretlendiğinden işaretçinin hangi nesneyi gösterdiğini kontrol eder.
Bu, bir alt sınıftaki bir işlevi geçersiz kılmaktan farklıdır. Bu durumda, meyve işaretçisi Fruit :: color () 'i çağırır.
Şimdi bir "saf sanal işlev" fikri ortaya çıkıyor. Saflığın onunla hiçbir ilgisi olmadığı için oldukça talihsiz bir ifade. Temel sınıf yönteminin asla çağrılmaması gerektiği anlamına gelir. Gerçekten saf bir sanal işlev çağrılamaz. Ancak yine de tanımlanması gerekir. Bir işlev imzası bulunmalıdır. Birçok kodlayıcı, eksiksizlik için boş bir uygulama {} yapar, ancak derleyici değilse dahili olarak bir tane oluşturur. Bu durumda, işaretçi Fruit konumunda olsa bile işlev çağrıldığında Banana :: color (), color () öğesinin tek uygulaması olduğu için çağrılır.
Şimdi bulmacanın son parçası: inşaatçılar ve yıkıcılar.
Saf sanal kurucular tamamen yasadışıdır. Bu sadece çıktı.
Ancak saf sanal yıkıcılar, temel sınıf örneğinin oluşturulmasını yasaklamak istediğinizde işe yarar. Temel sınıfın yıkıcısı saf sanal ise yalnızca alt sınıflar örneklenebilir. kural 0'a atamaktır.
virtual ~Fruit() = 0; // pure virtual
Fruit::~Fruit(){} // destructor implementation
Bu durumda bir uygulama oluşturmanız gerekir. Derleyici bunun ne yaptığınızı bilir ve doğru yaptığınızdan emin olur ya da derlemek için ihtiyaç duyduğu tüm işlevlere bağlanamayacağından kasten şikayet eder. Sınıf hiyerarşinizi nasıl modellediğiniz konusunda doğru yolda değilseniz hatalar kafa karıştırıcı olabilir.
Yani bu durumda Meyve örnekleri oluşturmak yasaktır, ancak Muz örnekleri oluşturmanıza izin verilir.
Bir Banana örneğine işaret eden Meyve işaretçisini silme çağrısı, önce Banana :: ~ Banana () öğesini ve ardından her zaman Fuit :: ~ Fruit () öğesini çağırır. Çünkü ne olursa olsun, bir alt sınıf yıkıcı dediğinizde, temel sınıf yıkıcı bunu izlemelidir.
Kötü bir model mi? Tasarım aşamasında daha karmaşıktır, evet, ancak çalışma zamanında doğru bağlantının yapılmasını ve tam olarak hangi alt sınıfa erişildiği konusunda belirsizliğin olduğu bir alt sınıf işlevinin gerçekleştirilmesini sağlayabilir.
Yalnızca genel veya belirsiz işaretçiler olmadan tam sınıf işaretçileri geçecek şekilde C ++ yazarsanız, sanal işlevlere gerçekten gerek yoktur. Ancak, türlerin çalışma zamanı esnekliğine ihtiyacınız varsa (Apple Banana Orange ==> Meyve'de olduğu gibi) işlevler, daha az yedekli kodla daha kolay ve çok yönlü hale gelir. Artık her meyve türü için bir işlev yazmak zorunda değilsiniz ve her meyvenin renge () kendi doğru işlevi ile yanıt vereceğini biliyorsunuz.
Umarım bu uzun soluklu açıklama, şeyleri karıştırmaktan ziyade kavramı sağlamlaştırır. Orada bakmak ve yeterince bakmak ve aslında onları çalıştırmak ve onlarla karışıklık bakmak için çok iyi örnekler vardır ve bunu elde edersiniz.