Sanal yöntemler genellikle işlev işaretçilerinin depolandığı sanal yöntem tabloları (kısaca seçilebilir) aracılığıyla uygulanır. Bu, asıl aramaya dolaysızlık ekler (sadece vtable'dan çağrılacak fonksiyonun adresini getirmeli, sonra onu çağırmalıyız - tam olarak onu çağırmak yerine). Tabii ki, bu biraz zaman ve biraz daha kod alır.
Bununla birlikte, ille de yavaşlamanın ana nedeni değildir. Asıl sorun, derleyicinin (genellikle / genellikle) hangi fonksiyonun çağrılacağını bilmemesidir . Dolayısıyla satır içi yapamaz ya da başka bir optimizasyon gerçekleştiremez. Bu tek başına bir düzine anlamsız talimat ekleyebilir (kayıtları hazırlamak, çağırmak, daha sonra durumu geri yüklemek) ve görünüşte alakasız optimizasyonları engelleyebilir. Dahası, birçok farklı uygulamayı çağırarak çılgın gibi dallarsanız, diğer yollarla çılgın gibi dallanacağınız hitlere benzer şekilde katlanırsınız: Önbellek ve dal tahmincisi size yardımcı olmaz, dallar mükemmel bir öngörülebilirden daha uzun sürer dalı.
Büyük ama : Bu performans isabetleri genellikle madde için çok küçük. Yüksek performanslı bir kod oluşturmak isteyip istemediğinize endişe verici bir sıklıkta çağrılacak sanal bir fonksiyon eklemeyi düşünebilirsiniz. Ancak, aynı zamanda diğer dallanma araçlarla sanal işlev çağrıları yerine (unutmayın if .. else
, switch
işlev işaretçileri, vs.) temel sorununu çözmez - çok iyi yavaş olabilir. Sorun (eğer varsa) sanal işlevler değil (gereksiz) dolaylı yüklemelerdir.
Düzenleme: Arama talimatlarındaki fark diğer cevaplarda açıklanmıştır. Temel olarak, statik ("normal") bir çağrının kodu:
- Çağrılan işlevin bu kayıtları kullanmasına izin vermek için yığındaki bazı kayıtları kopyalayın.
- Argümanları önceden tanımlanmış konumlara kopyalayın, böylece çağrılan işlev, çağrıldığı yerden bağımsız olarak bunları bulabilir.
- Dönüş adresini it.
- Bir derleme zamanı adresi olan fonksiyon koduna dallama / atlama ve dolayısıyla derleyici / linker tarafından ikili kodda kodlanmış.
- Önceden tanımlanmış bir konumdan dönüş değerini alın ve kullanmak istediğimiz kayıtları geri yükleyin.
Sanal bir çağrı, işlev adresinin derleme zamanında bilinmemesi dışında tamamen aynı şeyi yapar. Bunun yerine, birkaç talimat ...
- Nesneden, her sanal işlev için bir işlev işaretçisi dizisine (işlev adresleri) işaret eden vtable işaretçisini alın.
- Vtable'den doğru fonksiyon adresini bir sicile kaydedin (derleme zamanında doğru fonksiyon adresinin saklandığı indekse karar verilir).
- Kodlanmış bir adrese atlamak yerine, o kayıttaki adrese atlayın.
Dallara gelince: Dal, bir sonraki komutun çalıştırılmasına izin vermek yerine başka bir komutla atlayan herhangi bir şeydir. Bunlar arasında if
, switch
bazen çeşitli döngüler, fonksiyon çağrıları vb ve olmayan derleyici uygular şeyler parçaları aslında başlık altında bir şube ihtiyacı olduğu şekilde dal gibi görünüyor. Bkz Neden sırasız dizilerde daha hızlı sıralanmış bir dizi işliyor? Bunun neden yavaş olabileceğine, işlemcilerin bu yavaşlamaya karşı koymak için ne yaptığı ve bunun nasıl bir tedavi olmadığı.