Cevabımı daha iyi okumak için bir konuşma şeklinde yanıtladım:
Neden sanal işlevlere ihtiyacımız var?
Polimorfizm yüzünden.
Polimorfizm nedir?
Temel imlecin türetilmiş yazı nesnelerini de gösterebilmesi.
Polimorfizm'in bu tanımı nasıl sanal fonksiyonlara ihtiyaç duyuyor?
Erken bağlama yoluyla .
Erken bağlama nedir?
C ++ 'da erken bağlama (derleme zamanı bağlama), program yürütülmeden önce bir işlev çağrısının sabitlendiği anlamına gelir.
Yani...?
Bu nedenle, bir işlevin parametresi olarak bir taban türü kullanırsanız, derleyici yalnızca temel arabirimi tanır ve bu işlevi türetilmiş sınıflardan herhangi bir bağımsız değişkenle çağırırsanız, dilimlenir, bu da olmasını istemediğiniz şeydir.
Eğer olmasını istediğimiz şey bu değilse, buna neden izin verilir?
Çünkü Polimorfizme ihtiyacımız var!
O halde Polimorfizmin faydası nedir?
Temel tür işaretçisini tek bir işlevin parametresi olarak kullanabilirsiniz ve daha sonra programınızın çalışma zamanında türetilmiş tür arabirimlerinin her birine (ör. Üye işlevleri) herhangi bir sorun olmadan, bu tekin kayıttan çıkarılmasını kullanarak erişebilirsiniz. temel işaretçi.
Hala hangi sanal fonksiyonların işe yaradığını bilmiyorum ...! Ve bu benim ilk sorumdu!
çünkü sorunuzu çok erken sordunuz!
Neden sanal işlevlere ihtiyacımız var?
Temel işaretçiyle türetilmiş sınıflardan birindeki bir nesnenin adresine sahip bir işlev çağırdığınızı varsayın. Yukarıda bahsettiğimiz gibi, çalışma zamanında, bu işaretçi kayıttan çıkarıldı, şimdiye kadar iyi, ancak, "türetilmiş sınıfımızdan" bir yöntem (== bir üye işlevi) yürütülmesini bekliyoruz! Ancak, aynı sınıfta (aynı başlığa sahip bir yöntem) temel sınıfta zaten tanımlanmış, peki programınız neden diğer yöntemi seçmek için uğraşsın ki? Başka bir deyişle, bu senaryoyu daha önce normalde gördüğümüz şeylerden nasıl anlatabilirsiniz?
Kısa cevap "tabandaki bir sanal üye işlevi" ve biraz daha uzun bir cevap, "bu adımda, program temel sınıfta sanal bir işlev görürse, kullanmaya çalıştığınızı bilir (fark eder) polimorfizm "ve bu nedenle aynı başlığa sahip, ancak - beklenmedik şekilde - farklı bir uygulamaya sahip olan başka bir yöntem bulmak için türetilmiş sınıflara gider ( v-table , geç bağlama biçimi kullanılarak) .
Neden farklı bir uygulama?
Parmak eklemi! Git güzel bir kitap oku !
Tamam, bekle bekle bekle, neden türetilmiş tip işaretçileri kullanabiliyorsa, neden baz işaretçileri kullanmak rahatsız olur? Yargıç sizsiniz, tüm bu baş ağrısına değer mi? Şu iki parçacığa bakın:
// 1:
Parent* p1 = &boy;
p1 -> task();
Parent* p2 = &girl;
p2 -> task();
// 2:
Boy* p1 = &boy;
p1 -> task();
Girl* p2 = &girl;
p2 -> task();
Tamam, ben 1 hala 2 daha iyi olduğunu düşünüyorum rağmen , ya da böyle 1 yazabilirsiniz :
// 1:
Parent* p1 = &boy;
p1 -> task();
p1 = &girl;
p1 -> task();
ve ayrıca, bunun henüz size açıkladığım tüm şeylerin sadece bir kullanımı olduğunu bilmelisiniz. Bunun yerine, örneğin programınızda, sırasıyla türetilmiş sınıfların her birinden yöntemleri kullanan bir işlevin bulunduğu bir durumu varsayalım (getMonthBenefit ()):
double totalMonthBenefit = 0;
std::vector<CentralShop*> mainShop = { &shop1, &shop2, &shop3, &shop4, &shop5, &shop6};
for(CentralShop* x : mainShop){
totalMonthBenefit += x -> getMonthBenefit();
}
Şimdi, bunu baş ağrısı olmadan tekrar yazmaya çalışın !
double totalMonthBenefit=0;
Shop1* branch1 = &shop1;
Shop2* branch2 = &shop2;
Shop3* branch3 = &shop3;
Shop4* branch4 = &shop4;
Shop5* branch5 = &shop5;
Shop6* branch6 = &shop6;
totalMonthBenefit += branch1 -> getMonthBenefit();
totalMonthBenefit += branch2 -> getMonthBenefit();
totalMonthBenefit += branch3 -> getMonthBenefit();
totalMonthBenefit += branch4 -> getMonthBenefit();
totalMonthBenefit += branch5 -> getMonthBenefit();
totalMonthBenefit += branch6 -> getMonthBenefit();
Ve aslında, bu yine de tartışmalı bir örnek olabilir!