C++ OOP подробно обяснение и как трябва да го използвате във вашия код

Да преминем към темата: Какво е ООП?

Обектно-ориентираното програмиране (ООП) емодел за компютърно програмиранеизползван от почти всеки разработчик в определен момент от техния живот на кодиране. Това е една от доминиращите парадигми за програмиране и се превърна в мейнстрийм от 1990 г. насам.

ООП се учи като стандартен начин за писане на код в образователни програми, „въпреки че това не е най-добрият начин“. Но бих казал, че това е най-добрият начин да напишете ефективна програма за начинаещи. Това е главно защото концепцията за ООП е естествена за повечето хора.

Повечето от популярните езици за програмиране поддържат ООП, включително C++. Това е и основната характеристика на езика C++. И ще използвате ООП през повечето време, за да напишете отлична C++ програма.

Дефиниция на ООП в програмирането на C++

Както името му разказва историята — OOP работи, използвайки концепцията за обекти за проектиране на софтуер. Той пакетира софтуерна програма в многопо-опростени модуленкод, което позволява по-лесно манипулиране и поддръжка.

Клас

За да създадем модулен обект, се нуждаем от план за многократна употреба, наречен клас. Class е дефиниран от потребителя тип данни в C++. Той се различава от другите примитивни типове данни (int, bool, char и т.н.), тъй като можем да го персонализираме.

Е, как да персонализираме класа? Можем да конструираме атрибути (променливи данни) и методи (функция) в клас, за да формираме нов тип данни. Променливите дефинират атрибутите на класа, докато методите се използват за извършване на някои действия, които обикновено манипулират атрибутите на класа.

Атрибути — Да речем, че искаме да създадем клас, наречен Fruit, който съдържа атрибут като price. Можем просто да декларираме променлива с тип данни float вътре в Fruit.

Методи — Ако искаме да имаме метод, който определя цената на плодовете. Можем да дефинираме метод, наречен setPrice вътре в класа.

Как изглежда нашият план:

class Fruit{
public:
   void setPrice(float new_price){price = new_price;}
private:
   float price;
};

Досега сме създали само план (клас), наречен Fruit. За да създадем обект, трябва да извикаме класа Fruit с името на обекта, подобно на други примитивни типове данни.

int main(){
   Fruit banana;
   Fruit apple;
}

Примерът по-горе създава само екземпляри на обект чрез извикване на конструктора по подразбиране, генериран от C++ компилатора. Защото ние никога не посочваме конструктор.

Конструктор

И така, какво е конструктор? Конструкторът е метод, който извиква създаването на обект.

Обикновено искаме да изпълним някои методи на класа или да дефинираме членовете на променливата на класа, когато създаваме нов обект. Тук на помощ идва конструкторът. Можете да проверите тази страница, за да научите повече за конструкторите.

Можем да декларираме конструктора, както следва:

class Fruit{
public:
   Fruit(float _price, std::string _color){
      price = _price;
      color = _color;
   }  
   void setPrice(float new_price){price = new_price;}
private:
   float price;
   std::string color;  
};

Както можете да видите, конструкторът по-горе (Fruit()) изисква два аргумента: _price и _color. Конструкторът ни помага да създаваме значими данни вътре в обектите по време на тяхното създаване:

int main(){
   Fruit banana(1.25, "yellow");
   Fruit apple(1.60, "red");
}

4 Основни понятия на ООП

Четири основни концепции правят C++ прекалено силен (OOP):

1. Капсулиране

Капсулирането е опаковането на важна информация вътре в обект. С други думи, променливите и методите се съхраняват вътре в обекта при неговото създаване.

Капсулирането предотвратява нежелан достъп извън класа. Тази концепция е полезна за защита на използването на вашата програма. Вероятно не искате вашите клиенти да направят някои катастрофални промени във вашия софтуер.

За да реализираме това ограничение, имаме нужда от нещо, което ни позволява да уточним „нивото на защита“. И тук се намесват модификаторите за достъп.

Модификатори за достъп

Модификаторите за достъп са public и private, както виждате в примера по-горе. (Има друг, наречен protected, повече за това по-късно)

Можем да посочим членовете на класа като public или private. По подразбиране всички членове на клас са private, освен ако не са изрично обозначени като public.

Публичните членове могат да бъдат достъпни директно от всеки потребител на обект, но личните членове могат да бъдат достъпни само от самия обект.

Като вземем примера по-горе, декларирахме price като частен член, защото не искаме потребителите да имат директен достъп до него. Дефинирахме methodsetPriceкато публичен член, за да позволим на други потребители да задават price само чрез изрично извикване на метода.

Пример:

int main(){
   Fruit banana(1.25, "yellow");
   
   // error   
   std::cout << banana.color << std::endl;
   }

Обектът banana няма директен достъп до променливата на класа color в main().

Модификаторите за достъп помагат да се ограничи използването на определени членове на класа. Можете да се обърнете към това пълно ръководство, за да научите повече за модификаторите на достъп.

2. Абстракция

Абстракцията на данни в OOP означавапоказване само на съществената информациядокатоскриване на детайлитеот крайния потребител. Тази концепция е разширение на капсулирането.

В класа абстракцията се отнася до отделянето на интерфейса на класа от детайлите на изпълнението.

Ако все още не можете да го получите, можете да го разберете като - „Виждате само това, което аз избера да ви покажа“

Абстракцията ни позволява да използваме ясни класове, за да изразим сложни детайли.

Да вземем пример от шофирането на кола:

Не е нужно да знаете как работи двигателят, за да управлявате кола. Не е нужно да разбирате включеното инженерство: как се извършва предаването на мощността, как работи охладителната система или как шасито е проектирано да понесе тежестта на автомобила бла бла бла...

Трябва само да знаете кой педал да натиснете за ускоряване или спиране и как да управлявате колата, за да завиете. Всички детайли са скрити вътре, за да предпазят потребителя и неговия производител.

Това е подобно на C++ OOP. Нека видим как прилагаме абстракция в C++:

fruit.h

class Fruit{
public:
   void increasePrice(float percentage);
private:
   float price;
};

fruit.cpp

void Fruit::increasePrice(float percentage)
{
   price *= 1.0 + (percentage / 100);
}

Обикновено потребителите могат да видят само заглавния файл, fruit.hно не и изходния файл, fruit.cpp.

Потребителите могат да взаимодействат с класа Fruit чрез функцията increasePrice(). Но те не трябва да знаят подробностите за внедряването на increasePrice() (което се крие във fruit.cpp).

3. Наследство

Наследяването позволява на класовете да извличат свойства и характеристики от друг клас.

Това е една от най-важните характеристики на OOP, тъй като поддържа повторно използване. Не е необходимо да предефинирате друг клас с подобни характеристики като класа, който сте дефинирали по-рано.

Например, нека използваме Fruit, който дефинирахме по-рано:

class Fruit{
public:
   void setPrice(float new_price){price = new_price;}
protected:
   float price;
   std::string color;  
};

Можем да извлечем други класове от Fruit като Durian и Strawberry. Така че не е необходимо да дефинираме отново членските променливи — price и color.

Друго предимство на наследяването е, че производните класове могат да имат различни членски променливи, като thorns и is_berry:

class Durian : public Fruit {
private:
   bool thorns = true;
};
class Strawberry : public Fruit {
private: 
   bool is_berry = false;
};

Durianи Strawberry са известни като производни класове. За разлика от това, Fruit, наследен от другите класове, се нарича базов клас.

Някои от вас може вече да забележат друг спецификатор за достъп — protected в Fruit . protected е предназначен за използване при наследяване на клас.

Производен клас не наследява достъп до частни данни членове на своя базов клас. За да се предотврати директен достъп на други потребители до price и color, като същевременно се позволи на Durian и Strawberry да наследят и двете членски променливи, се използва protected.

Спецификаторите за достъп също се използват при наследяване при дефиниране на производните класове. За този пример използваме публично наследяване.

Макар чеобикновено използваме публично наследяванев C++, може да искате да проверите кога ще приложите другите две, частно и защитено наследяване, в тази връзка.

4. Полиморфизъм

„Полиморфизъм“ означава „имащ множество форми“ на гръцки. В OOP това означава способността на дадена функция да се изпълнява по различен начин в зависимост от това как се извиква.

Претоварване

В C++ полиморфизмът обикновено се постига чрез претоварване,което също е известно като полиморфизъм по време на компилиране. И има два вида претоварване: „претоварване на оператор“ и претоварване на функция. Претоварването на оператора е по-трудно за разбиране, така че няма да го обсъждаме тук заради простотата на тази статия.

Претоварването на функциите е много лесно. Ще разберете какво имам предвид, като прочетете примера по-долу:

class Fruit{
public:
   Fruit(float _price){price = _price;}
   void increasePrice(double percentage)
   {
      price *= 1.0 + (percentage / 100);
   }
   void increasePrice(int cents)
   {
      price += cents/100.0;
   }
private:
   float price;
};
int main()
{
   Fruit orange;
   Fruit apple;
   Orange.setPrice(0.60);
   Apple.setPrice(0.80);
   orange.increasePrice(0.20);
   apple.increasePrice(10);

Резултат:

Price of orange: 0.72
Price of apple: 0.90

Дефинирахме две функции с точно едно и също име, но с различни типове данни на аргументи, едната е double, а другата е int. Програмата ще изпълнява всяка функция в зависимост от входовете.

Така че, когато подадете параметър double, increasePrice(0.20) увеличи цената на портокала с 20%. Но ако подадете параметър int, increasePrice(10) повишава цената на ябълката с 10 цента.

Отмяна

Полиморфизмът може да бъде направен и по друг начин: „Отмяна“. Този подход се нарича полиморфизъм по време на изпълнение.

За да приложите отмяна, трябва да декларирате virtual функция в базовия клас, докато дефинирате друга функция в производния клас със същото име на функция и типове аргументи.

class Fruit{
public:
   virtual void printSkinColor() 
   { 
      std::cout << "The skin colour of fruit is " << color << "\n";
   }
protected:
   std::string color;  
};
class Durian : public Fruit {
public:
   void printSkinColor()
   {
      std::cout << "The skin colour of durian is " << color << "\n";
   }
};

В крайна сметка ще получите различни резултати, като извикате различни класове’ printSkinColor().

Полиморфизмът, използващ претоварване и замяна, поддържа последователност и подобрява четливостта на кода. Той също така насърчава повторното използване на кода.

Заключение

Това ни води до края на представянето на обектно-ориентираното програмиране на C++.

Изучаването на C++ обикновено е предизвикателство, но ООП винаги е отличен избор за начало. Ще намерите повече радост, докато учите показатели (Е, десетки хора се отказаха, но вярвам, че ще се забавлявате с това!).

Ако харесвате този блог, покажете подкрепата си с „ръкопляскане“. Не забравяйте, че можете да пляскате до 50 пъти.

Кодиране на ниво нагоре

Благодарим ви, че сте част от нашата общност! Преди да тръгнеш:

🚀👉 Поставяне на разработчици като вас в топ стартиращи фирми и технологични компании