Sanal işlev - Virtual function

İçinde nesne yönelimli programlama gibi dillerde C ++, ve Nesne Pascal, bir sanal işlev veya sanal yöntem kalıtsaldır ve geçersiz işlevi veya yöntem hangisi için dinamik gönderim kolaylaştırılır. Bu kavram, (çalışma zamanının) önemli bir parçasıdır çok biçimlilik kısmı nesne yönelimli programlama (OOP). Kısacası, sanal bir işlev yürütülecek bir hedef işlevi tanımlar, ancak hedef derleme zamanında bilinmeyebilir.

Gibi çoğu programlama dili Java, PHP ve Python, tüm yöntemleri varsayılan olarak sanal olarak değerlendirin[1] ve bu davranışı değiştirmek için bir değiştirici sağlamayın. Bununla birlikte, bazı diller, yöntemlerin türetilmiş sınıflar tarafından geçersiz kılınmasını önlemek için değiştiriciler sağlar ( final anahtar kelime Java[2] ve PHP[3]).

Amaç

Sanal işlev kavramı aşağıdaki sorunu çözer:

Nesne yönelimli programlamada, türetilmiş bir sınıf bir temel sınıftan miras aldığında, türetilmiş sınıfın bir nesnesine bir Işaretçi veya referans türetilmiş sınıf türü yerine temel sınıf türünün. Türetilmiş sınıf tarafından geçersiz kılınan temel sınıf yöntemleri varsa, aslında böyle bir başvuru veya işaretçi tarafından çağrılan yöntem, işaretçi veya başvurunun bildirilen türüne göre 'erken' (derleyici tarafından) veya 'geç' bağlanabilir. (yani, dilin çalışma zamanı sistemi tarafından), atıfta bulunulan nesnenin gerçek türüne göre.

Sanal işlevler 'geç' çözülür. Söz konusu işlev temel sınıfta 'sanal' ise, en çok türetilen sınıfın işlevin gerçekleştirilmesi, işaretçi veya başvurunun bildirilen türüne bakılmaksızın, atıfta bulunulan nesnenin gerçek türüne göre çağrılır. 'Sanal' değilse, yöntem 'erken' çözümlenir ve çağrılan işlev, işaretçi veya başvurunun bildirilen türüne göre seçilir.

Sanal işlevler, bir programın kodun derlendiği anda var olması gerekmeyen yöntemleri çağırmasına izin verir.

C ++ 'da, sanal yöntemler başına ekleyerek beyan edilir gerçek temel sınıftaki işlevin bildirimine anahtar kelime. Bu değiştirici, bu yöntemin türetilmiş sınıflardaki tüm uygulamaları tarafından miras alınır, yani birbirlerini aşmaya ve geç bağlanmaya devam edebilirler. Ve temel sınıfa ait yöntemler sanal yöntemi çağırsa bile, bunun yerine türetilmiş yöntemi çağıracaklardır. Aşırı yükleme bir sınıftaki iki veya daha fazla yöntem aynı yöntem adına ancak farklı parametrelere sahip olduğunda oluşur. Geçersiz kılma aynı yöntem adı ve parametreleri ile iki yönteme sahip olmak anlamına gelir. Aşırı yükleme, işlev eşleştirme olarak da adlandırılır ve dinamik işlev eşlemesi olarak geçersiz kılma olarak adlandırılır.

Misal

Hayvanın Sınıf Diyagramı

Örneğin, bir temel sınıf Hayvan sanal bir işlevi olabilir Yemek. Alt sınıf Lama uygular Yemek alt sınıftan farklı Kurtama biri çağırabilir Yemek Animal olarak anılan herhangi bir sınıf örneğinde ve Yemek belirli alt sınıfın davranışı.

sınıf Hayvan { halka açık:  // Kasıtlı olarak sanal değil:  geçersiz Hareket(geçersiz) {    std::cout << "Bu hayvan bir şekilde hareket ediyor" << std::son;  }  gerçek geçersiz Yemek(geçersiz) = 0;};// "Animal" sınıfı istenirse Eat için bir tanıma sahip olabilir.sınıf Lama : halka açık Hayvan { halka açık:  // Sanal olmayan Move işlevi miras alınır ancak geçersiz kılınmaz.  geçersiz Yemek(geçersiz) geçersiz kılmak {    std::cout << "Lamalar ot yer!" << std::son;  }};

Bu, bir programcının sınıftaki nesnelerin bir listesini işlemesine izin verir. Hayvanher birine sırayla yemek yemesini söyleyerek (arayarak Yemek), listede ne tür bir hayvan olabileceğini, her bir hayvanın nasıl yediğini veya olası hayvan türlerinin tam setinin ne olabileceğini bilmeye gerek kalmadan.

Yukarıdaki örneği C'de uygulayarak sanal işlevlerin nasıl çalıştığını daha iyi görebiliriz.

#Dahil etmek <stdio.h>/ * bir nesne sınıfına işaret ediyor ... * /yapı Hayvan {    sabit yapı Hayvan Sınıfı * sınıf;};Animal.Eat sanal işlevini içeren / * * /yapı Hayvan Sınıfı {    geçersiz (*Yemek)(yapı Hayvan *); // 'sanal' işlev };/ * Animal.Move sanal bir işlev olmadığından   yukarıdaki yapıda değildir. * /geçersiz Hareket(yapı Hayvan * kendini){    printf("<% P konumundaki Hayvan> bir şekilde hareket etti n", (geçersiz *) kendini);}/ * Animal.Move'u doğrudan çalıştıran Move'un aksine,   Eat, derleme sırasında hangi işlevi (varsa) çağıracağını bilemez.   Animal.Eat, yalnızca Eat çağrıldığında çalışma zamanında çözülebilir. * /geçersiz Yemek(yapı Hayvan * kendini){    sabit yapı Hayvan Sınıfı * sınıf = *(sabit geçersiz **) kendini;    Eğer (sınıf->Yemek)         sınıf->Yemek(kendini); // Animal.Eat'i çalıştırın    Başka        fprintf(Stderr, "Yemek uygulanmadı n");}/ * Lama uygulaması.Eat this is the target function    'void Eat (struct Animal *)' ile çağrılacak. * /statik geçersiz _Lama_eat(yapı Hayvan * kendini){    printf("<% P'de lama> Lama ot yer! n", (geçersiz *) kendini);    }/ * sınıfı başlat * /sabit yapı Hayvan Sınıfı Hayvan = {(geçersiz *) 0}; // temel sınıf Animal.Eat uygulamıyorsabit yapı Hayvan Sınıfı Lama = {_Lama_eat};  // ancak türetilmiş sınıf varint ana(geçersiz){   / * sınıfının örneği olarak nesneleri init * /   yapı Hayvan hayvan = {& Hayvan};   yapı Hayvan lama = {& Lama};   Hareket(& hayvan); // Animal.Move   Hareket(& lama);  // Llama.Move   Yemek(& hayvan);  // Animal.Eat çözümlenemiyor, böylece stderr için "Uygulanmadı" yazdır   Yemek(& lama);   // Llama.Eat'i çözer ve çalıştırır}

Soyut sınıflar ve saf sanal işlevler

Bir saf sanal işlev veya saf sanal yöntem türetilmiş sınıf değilse, türetilmiş bir sınıf tarafından uygulanması gereken sanal bir işlevdir Öz. Saf sanal yöntemler içeren sınıflar "soyut" olarak adlandırılır ve doğrudan örneklenemezler. Bir alt sınıf Bir soyut sınıfın örneği, yalnızca miras alınan tüm saf sanal yöntemler bu sınıf veya bir ana sınıf tarafından uygulandıysa doğrudan başlatılabilir. Saf sanal yöntemlerin genellikle bir bildirimi vardır (imza ) ve tanım yok (uygulama ).

Örnek olarak, soyut bir temel sınıf Matematik Sembolü saf bir sanal işlev sağlayabilir doOperation ()ve türetilmiş sınıflar Artı ve Eksi uygulamak doOperation () somut uygulamalar sağlamak. Uygulama doOperation () mantıklı olmaz Matematik Sembolü sınıf olarak Matematik Sembolü davranışı yalnızca her bir tür (alt sınıf) için tanımlanan soyut bir kavramdır. Matematik Sembolü. Benzer şekilde, belirli bir alt sınıf Matematik Sembolü uygulaması olmadan tamamlanmayacaktırdoOperation ().

Saf sanal yöntemlerin tipik olarak sınıfta onları bildiren hiçbir uygulaması olmasa da, C ++ 'daki saf sanal yöntemlerin, uygunsa, türetilmiş bir sınıfın delege edebileceği geri dönüş veya varsayılan davranış sağlayarak bildirim sınıflarında bir uygulama içermesine izin verilir.[4]

Saf sanal işlevler, yöntem bildirimlerinin bir arayüz - Java'daki arabirim anahtar kelimesinin açıkça belirttiğine benzer. Böyle bir kullanımda, türetilmiş sınıflar tüm uygulamaları sağlayacaktır. Böyle bir tasarım deseni arayüz olarak hizmet veren soyut sınıf, sadece saf sanal işlevler, ancak veri üyeleri veya sıradan yöntemler yok. C ++ 'da, arabirimler olarak bu tür tamamen soyut sınıfların kullanılması işe yarar çünkü C ++ çoklu miras. Ancak, birçok OOP dili çoklu kalıtımı desteklemediğinden, genellikle ayrı bir arayüz mekanizması sağlarlar. Bir örnek, Java programlama dili.

İnşaat ve yıkım sırasında davranış

Diller davranışlarında farklılık gösterirken kurucu veya yıkıcı bir nesnenin çalışması. Bu nedenle, yapıcılarda sanal işlevlerin çağrılması genellikle önerilmez.

C ++ 'da "temel" işlev çağrılır. Spesifik olarak, mevcut kurucunun sınıfından daha fazla türetilmeyen en türetilmiş işlev çağrılır.[5] Bu işlev saf bir işlevse, tanımlanmamış davranış oluşur.

Java ve C # 'de türetilmiş uygulama çağrılır, ancak bazı alanlar henüz türetilmiş kurucu tarafından başlatılmamıştır (yine de varsayılan sıfır değerlerine başlatılmış olsalar da).[6] Biraz tasarım desenleri, benzeri Soyut Fabrika Modeli, bu yeteneği destekleyen dillerde bu kullanımı aktif olarak tanıtın.

Sanal yıkıcılar

Nesne yönelimli diller tipik olarak, nesneler oluşturulduğunda ve yok edildiğinde bellek tahsisini ve tahsisi kaldırmayı otomatik olarak yönetir. Bununla birlikte, bazı nesne yönelimli diller, istenirse özel bir yıkıcı yöntemin uygulanmasına izin verir. Söz konusu dil otomatik bellek yönetimi kullanıyorsa, çağrılan özel yıkıcının (bu bağlamda genellikle sonlandırıcı olarak adlandırılır) söz konusu nesne için uygun olduğu kesindir. Örneğin, Hayvan'ı miras alan Wolf türünde bir nesne oluşturulursa ve her ikisinin de özel yıkıcıları varsa, çağrılan, Wolf'ta bildirilen olacaktır.

Manuel bellek yönetimi bağlamlarında, durum, özellikle statik göndermeyle ilgili olarak daha karmaşık olabilir. Wolf türünde bir nesne oluşturulur ancak bir Hayvan işaretçisi tarafından işaret edilirse ve silinen bu Hayvan işaretçisi tipiyse, çağrılan yıkıcı aslında Animal için tanımlanmış olabilir ve yıkıcı sanal değilse Wolf için değil . Bu, özellikle yıkıcılar sanal değilse davranışın ortak bir programlama hatası kaynağı olduğu C ++ için geçerlidir.

Ayrıca bakınız

Referanslar

  1. ^ "Çok Biçimlilik (Java ™ Öğreticileri> Java Dilini Öğrenme> Arayüzler ve Kalıtım)". docs.oracle.com. Alındı 2020-07-11.
  2. ^ "Son Sınıfları ve Yöntemleri Yazma (Java ™ Öğreticileri> Java Dilini Öğrenme> Arayüzler ve Kalıtım)". docs.oracle.com. Alındı 2020-07-11.
  3. ^ "PHP: Son Anahtar Kelime - Manuel". www.php.net. Alındı 2020-07-11.
  4. ^ Saf sanal yıkıcılar - cppreference.com
  5. ^ Meyers, Scott (6 Haziran 2005). "İnşaat veya Yıkım Sırasında Asla Sanal İşlevleri Çağırma".
  6. ^ Ganesh, S.G. (1 Ağustos 2011). "Programlamanın Keyfi: Oluşturuculardan Sanal İşlevleri Çağırma".