Yuqorida biz bir qator misollarni ko’rib chiqdik, ularda ajdod sinfning ko’rsatkichlari yoki havolalaridan foydalanish mantiqni soddalashtirdi va kod miqdorini kamaytirdi. Virtual funksiyalar va polimorfizm. Biroq, biz muammoga duch keldik, bunda ajdod ko’rsatkichi yoki havolasi faqat ajdod metodlarini chaqiradi, avlodni emas. Masalan: #include class Parent {
public:
const char* getName() { return "Parent”; }
};
class Child: public Parent {
public:
const char* getName() { return "Child”; }
};
int main()
{
Child child;
Parent &rParent = child;
std::cout << ”rParent: ” << rParent.getName() << '\n';
}
rParent Parent sinfiga havola bo’lgani uchun Parent::getName() chaqiriladi, garchi biz aslida child obyektning Parent sinfiga havola ham.
Quyida biz virtual funktsiyalardan foydalangan holda ushbu muammoni qanday hal qilishni ko’rib chiqamiz.
C++ tilidagi virtual funksiya funksiyaning maxsus turi bo‘lib, chaqirilganda ajdod va bola sinflari o‘rtasida mavjud bo‘lgan “eng katta” avlod metodini bajaradi. Bu xususiyat polimorfizm deb ham ataladi. Signatura (nom, parametr turlari va usul doimiymi) va bola usulining qaytish turi ajdod-sinfning metodining imzosi va qaytish turiga mos kelganda, avlod metodi chaqiriladi. Bu metodlarni qayta aniqlash deyiladi (yoki "o'zgartirilgan usullar”).
Funksiyani virtual qilish uchun funksiya e’lonidan oldin virtual kalit so’zni ko’rsatish kifoya. Masalan:
#include class Parent
{
public:
virtual const char* getName() { return "Parent”; } // gobaBunu KaroueBoe caoBo virtual
class Child: public Parent {
public:
virtual const char* getName() { return "Child”; }
};
int main()
{
Child child;
Parent &rParent = child;
std::cout << "rParent: ” << rParent.getName() << '\n';
return 0;}
rParent avlod obyektining ajdodiga havola bo’lganligi sababli, odatda rParent.getName () ni qayta ishlashda Parent :: getName () chaqiriladi. Biroq, Parent :: getName () virtual funktsiya bo’lganligi sababli, kompilyator avlod sinflarida ushbu metodning qayta aniqlanishini ko’radi va kompilyator Child :: getName () ni topadi!
Keling, murakkabroq misolni ko’rib chiqaylik:
#include using namespace std;
class A
{
public:
virtual const char* getName() { return "A”; }
};
class B: public A
{
public:
virtual const char* getName() { return "B"; }
};
class C: public B {
public:
virtual const char* getName() { return "C"; }
};
class D: public C {
public:
virtual const char* getName() { return "D"; }
};
int main()
{
C c;
A &rParent = c;
cout << "rParent: " << rParent.getName() << '\n';
return 0;}
Sizningcha, bu dasturning natijasi qanday?
Keling, hamma narsani tartibda ko’rib chiqaylik:
-Birinchidan, C sinfining c obyekti yaratiladi.
-rParent A sinfining havolasi bo’lib, biz uni c obyektning A qismiga murojaat qilish uchun belgilaymiz.
-Keyin rParent.getName () metodi chaqiriladi.