Abstrakt funksiyalar va sinflar. Shu nuqtaga qadar biz barcha virtual funktsiyalarimizning ta’riflarini yozdik. Biroq, C++ sof virtual funksiyalar (yoki “mavhum funksiyalar”) deb ataladigan maxsus turdagi virtual funksiyalarni yaratishga imkon beradi, ularda umuman ta’rifi yo‘q! Ular avlod sinflari tomonidan qayta aniqlanadi.
Sof virtual lunktsiyani yaratishda virtual funktsiyani aniqlash (tanasini yozish) o’rniga, biz shunchaki 0 qiymatini beramiz.
#include using namespace std;
class Parent
{
public:
const char* sayHi() { return "Hi”; } // oddiy virtual bo’lmagan lunksiya
virtual const char* getName() { return "Parent”; } // oddiy virtual funksiya virtual int getValue() = 0; // toza virtual lunksiya
int doSomething() = 0; // kompilyatsiya xatosi: virtual bo’lmagan funksiyalarni //0 ni ta’minlab bo’lmaydi
};
int main()
{
return 0;
}
Shunday qilib, biz kompilyatorga aytamiz: "Avlod sinflari ushbu funksiyani amalga oshirish uchun javobgar bo’ladilar.”
Sof virtual funksiyadan foydalanish ikkita asosiy ta’sirga ega. Birinchidan, bir yoki bir nechta sof virtual funksiyalarga ega bo’lgan har qanday sinf obyektlarini yaratib bo’lmaydigan mavhum sinfga aylanadi! Agar biz Parent sinfining ob’ektini yaratsak nima bo’lishini ko’rib chiqamiz:
int main()
{
Parent parent; // biz mavhum sinf obyektlarini yarata olmaymiz,
//lekin tajriba uchun buni mumkin deb tasavvur qiling. parent.getValue(); // bu kod qatorining natijasi nima?
}
Biz getValue() metodini aniqlamaganimiz uchun parent.getValue() natijasi qanday? Ikkinchidan, mavhum ajdod-sinfning barcha avldo sinflari barcha sof virtual funktsiyalarni qayta aniqlashi kerak, aks holda ular ham mavhum sinflar hisoblanadi.
Sof virtual funktsiyaga misol.Amaliyotda sof virtual funksiyaning misolini ko’rib chiqamiz. Oldingi darslardan birida biz Animal ajdod sinfini va Cat va Dog avlod sinflarini yaratdik:
#include #include using namespace std; class Animal
{
protected:
string m_name;
Animal(string name)
{
m_name = name;
}
public:
string getName() { return m_name; } virtual const char* speak() { return "???"; }
};
class Cat: public Animal {
public:
Cat(string name)
: Animal(name)
{
}
virtual const char* speak() { return "Meow”; }
class Dog: public Animal {
public:
Dog(string name)
: Animal(name)
{
}
virtual const char* speak() { return "Woof"; }
};
Konstruktorni himoyalangan qilib, Animal sinfi obyektlarini yaratishni taqiqladik. Biroq, ikkita muammo saqlanib qolmoqda:
- Konstruktor hali ham avlod sinflari uchun mavjud bo’lib, Animal sinfi obyektlarini yaratishga imkon beradi.
- speak() metodini qayta aniqlamaydigan avlod sinflari hali ham bo’lishi mumkin.
Masalan:
class Lion: public Animal {
public:
Lion(string name)
: Animal(name)
{
}
// Biz speak () metodini qayta aniqlashni unutdik
};
int main()
{
Lion lion(MJohnM);
std::cout << lion.getName() << lion.speak() << ” deydi ” ;
}
Dastur natijasi: John ??? deydi
Nima bo’ldi? Biz speak () metodini qayta aniqlashni unutib qo‘ydik, shuning uchun lion.speak () Animal.speak () deb nomlandi va biz yuqoridagi natijani oldik.
Yechim sof virtual funksiyadan foydalanishdir:
#include #include using namespace std;
class Animal // Animal sinfi mavhum sinfdir {
protected:
std::string m_name; public:
Animal(std::string name)
: m_name(name)
{
}
std::string getName() { return m_name; }
virtual const char* speak() = 0; // sof virtual funksiya};
Bu yerda diqqat qilish kerak bo’lgan bir nechta narsa bor. Birinchidan, speak() endi sof virtual funktsiyadir. Bu shuni anglatadiki, Animal endi abstrakt ajdod-sinf bo’lib, biz protected spetsifikatsiyaga muhtoj emasmiz (garchi bu ortiqcha bo’lmasa ham). Ikkinchidan, bizning Lion sinfimiz Animal sinfining avlodi bo’lganligi sababli, lekin biz Lion :: speak () ni aniqlamaganimiz uchun, Lion ham abstrakt sinf hisoblanadi. Shuning uchun, agar biz quyidagi kodni kompilyatsiya qilishga harakat qilsak:
#include #include using namespace std;
class Animal // Animal sinfi mavhum sinfdir {
protected:
std::string m_name; public:
Animal(std::string name)
: m_name(name)
{
}
std::string getName() { return m_name; }
virtual const char* speak() = 0; // sof virtual fUnksiya
};
class Lion: public Animal {
public:
Lion(std::string name)
: Animal(name)
{
}
// speak() metodini qayta aniqlashni unutdik
};
int main()
{
Lion lion(MJohnM);
std::cout << lion.getName() << ” says ” << lion.speak() << '\n';
}
Keyin biz Lion abstrakt sinf ekanligini va abstrakt sinf obyektlarini yaratish mumkin emasligini bildiruvchi xatoga duch kelamiz. Bundan xulosa qilishimiz mumkinki, Lion sinfining obyektini yaratish uchun biz speak() metodini qayta aniqlashimiz kerak:
class Lion: public Animal {
public:
Lion(string name)
: Animal(name)
{
}
virtual const char* speak() { return "RAWRR!"; }
};
int main()
{
Lion lion(”John”);
cout << lion.getName() << ” ” << lion.speak() << ”deydi ”;
}
Endi quyidagi natijani olish mumkin: Jon RAWRR deydi!
Sof virtual funktsiya bizda ajdod sinfiga qo’ymoqchi bo’lgan funktsiyaga ega bo’lsak foydali bo’ladi, lekin realizatsiyani avlod sinflariga qoldiring. Abstrakt ajdod sinfning sof virtual funksiyasi avlod sinflarini ushbu funktsiyani qayta aniqlashga majbur qiladi, aks holda bu sinflarning obyektlarini yaratish mumkin bo’lmaydi.