петак, 16. октобар 2015.

Klase u C++ programskom jeziku – 2 deo



U prethodnom postu; možete ga pogledati ovde, sam vam predstavio jedan osnovni primer pravljenja i korišćenja klase koja je kodirana u istom fajlu vašeg programa. U poslovnom svetu to nije praksa i zato ću vam pokazati kako se pravi i poziva klasa koja je podeljena u header fajl i poseban fajl za klasu iz Visual Studio-a 2015. Ukoliko koristite neki drugi IDE, verovatno sami trebate napraviti fajlove ili je procedura nešto drugačija ili IDE odrađuje posao na svoj način. Važno je da je suština ista. U ovom postu opisujem isti program kao u prethodnom postu osim što je prepravljen i što su mu dodate neke stvari, pre svega radi pravilnije upotrebe klasa ali i dalje njihovog učenja. Kad pokrenete novi program, vi možete u prozoru Solution Explorer-a da kliknite na projekat desnim tasterom miša, zatim na Add i izaberite Class, kao na slici:


( Solution Explorer, dodavanje klase projektu )

Zatim je potrebno da izaberite C++ Class, i samo klikom na dugme Add pokrećete čarobnjaka za klase Generic C++ Class Wizard. Klasi je dovoljno dati naziv i pritisnuti dugme Finished. U našem primeru klasa se zove Animal.


( Generic C++ Class Witzard )

Čarobnjak za klase je dodao dva nova fajla u projekat; Animal.h i Animal.cpp. U fajlu Animal.h definišu se deklaracije promenjivih i funkcija dok se funkcije pišu u Animal.cpp fajlu. Kad pogledate u fajl Animal.h, možete videti da je IDE čarobnjak za wizard ubacio naziv i telo klase, ali i prazan konstruktor klase i destruktor iste. Pogledajte kod u fajlu Animal.h koji Visual Studio-a 2015 
generiše i pre nego što počnete da pišete klasu:

#pragma once

class Animal
{
public:
        Animal();
       ~Animal();

};

Šta je konstruktor, a šta je destruktor?

Konstruktor će te najbolje shvatiti ako ga posmatrate kao posebnu specijalnu funkciju koja služi da inicijalizuje vaše promenjive, funkcije ili objekte. Npr. ako želite da po defaultu svaka životinja ima 4 noge, ukoliko ne navedete drugačije, onda jednostavno dodelite promenjivoj legs 4 ali u konstruktoru. Konstruktor će te uvek prepoznati po tome što se on zove isto kao i klasa. Konstruktor ne vraća vrednosti ali i pored toga ne piše se sa ključnom rečju void.


Animal(string x_name, string x_species, string x_gender,
       unsigned short x_age, unsigned short x_weight, unsigned short x_legs)
       {
             x_age = 0;
             x_weight = 0;
             x_legs = 4;

             name = x_name;
             species = x_species;
             gender = x_gender;
             age = x_age;
             weight = x_weight;
             legs = x_legs;
            
      

U njemu se jednostavno vrši inicijalizacija koja ne zahteva upotrebu ključne reči return. Svaka klasa ima konstruktor, bez obzira da li ste ga vi napisali u vašem kodu ili ne. Jednostavno ukoliko niste napisali ni jedan konstruktor, vaš kompajler će ga dodati. Međutim konstruktor koji dodaje vaš kompajler je prazan. To u prevodu znači da ne radi ništa. To neće inicijalizovati vrednosti vaših praznih promenjivih. Pogledajte promenjivu legs koja je inicijalizovana u konstruktoru.

x_legs = 4;
legs = x_legs;

Navedeni kod takođe znači da je promenjiva legs po defaultu 4; kućni ljubimac ima 4 noge ako ne unesete nikakvu vrednost, mada ovaj program neće dozvoliti da ne unesete bilo koju vrednost iako ne obrađuje ulazne greške, ali shvatate poentu. Inače da promenjiva legs nije inicijalizovana, verovatno bi ste mislili da je vrednost promenjive legs jednaka 0 ali nije, nego bi u tom slučaju promenjiva legs sadržavala neki slučajno odabrani broj kog zovemo smeće. Zato morate inicijalizovati u konstruktoru promenjivu legs i dodati joj vrednost za koju smatrate defaultom. Prvo pogledajte kod koji se piše u header fajlu. On sadrži samo deklaracije, konstruktore i destruktor. 


#pragma once
#include <string>
using namespace std;

class Animal
{
private:

       string name;
       string species;
       string gender;
       unsigned short age;
       unsigned short weight;
       unsigned short legs;

       string MakeLower(string value);

public:

       string GetName();
       void SetName(string value);
       string GetSpecies();
       void SetSpecies(string value);
       string GetGender();
       void SetGender(bool value);
      
       unsigned short GetAge();
       void SetAge(unsigned short value);
       unsigned short GetWeight();
       void SetWeight(unsigned short value);
       unsigned short GetLegs();
       void SetLegs(unsigned short value);

       Animal(string x_name, string x_species, string x_gender,
             unsigned short x_age, unsigned short x_weight, unsigned short x_legs)
       {
             x_age = 0;
             x_weight = 0;
             x_legs = 4;

             name = x_name;
             species = x_species;
             gender = x_gender;
             age = x_age;
             weight = x_weight;
             legs = x_legs;
            
       }

       Animal();
       ~Animal();
      
};

U navedenom kodu imamo 2 konstruktora. Jedan je bez parametara, dok drugi zahteva atribute. Ukoliko ne bi ste imali konstruktor bez parametara vi ne bi ste mogli da deklarišete u programu klasu bez atributa. Vi možete imati više konstruktora ali svi moraju da se zovu isto kao i klasa i moraju da imaju različite atribute koje prihvataju. Koncept svojstava ili Property-ja kao u C# programskom jeziku u C++ ne postoji. Možete ih napraviti uz pomoć makroa ili da umesto Property-ja pišete funkcije koje prihvataju i podešavaju vrednost promenjive, kao što je urađeno u navedenom programu. U fajlu klase se pišu funkcije koje ste deklarisali u header-u. Konstruktor i destruktor koji dodaje Visual Studio-a 2015 i u fajl klase, nemojte brisati.

#include "stdafx.h"
#include "Animal.h"
#include <iostream>
#include <string>

string Animal::GetName()
{
       return name;

}

void Animal::SetName(string value)
{
       name = value;

}

string Animal::GetSpecies()
{
       return species;

}

void Animal::SetSpecies(string value)
{
       species = value;

}

string Animal::GetGender()
{
       return gender;

}

void Animal::SetGender(bool value)
{
       if (value == true) gender = "Male"; else gender = "Female";
      
}

unsigned short Animal::GetAge()
{
       return age;

}

void Animal::SetAge(unsigned short value)
{
       if (value > 100)
       {
             cout << endl << "Your pet can't be over 100 years old." << endl << endl;
             age = 0;
       }
       else
       {
             age = value;
       }

}

unsigned short Animal::GetWeight()
{
       return weight;

}

void Animal::SetWeight(unsigned short value)
{
       if (value > 10000)
       {
             cout << "Your pety can't be over 10000 kilos." << endl << endl;
             weight = 0;
       }
       else
       {
             weight = value;
       }

}

unsigned short Animal::GetLegs()
{
       return legs;

}

void Animal::SetLegs(unsigned short value)
{
       if (value > 1000)
       {
             cout << "Your pet can't have over 1000 legs." << endl << endl;
             legs = 0;
       }
       else
       {
             legs = value;
       }

}

Animal::Animal()
{
}

Animal::~Animal()
{
}

Kao što možete videti, sve funkcije koje ste deklarisali u header-u su u fajlu klase Animal.cpp U funkcijama za set-ovanje, promenu vrednosti možete implementirati koji god hoćete proračun bitan za program. Npr. funkcija SetGender proverava da li je vrednost tačna ili netačna i na osnovu toga menja vrednost privatne promenjive u Male ili Female dok funkcija GetGender samo vraća vrednost privatne promenjive gender. To je idealno ako vam treba promenjiva samo za čitanje vrednosti. Funkcija SetAge ispisuje poruku u CommandPromt-u ako ste uneli vrednost veću od 100 godina i podešava vaš unos na 0. U ovom programu je to urađeno samo radi što jednostavnijeg primera. Vaš fokus treba da je usmeren na klase u ovom primeru. Kad pozovete klasu Animal preko header direktive u vaš program, vi je jednostavno klasu deklarišete i koristite kao tip promenjive ili objekat.

#include "stdafx.h"
#include <iostream>
#include <string>
#include "Animal.h"
#include <algorithm>
using namespace std;

int main()
{
       string s_input;
    unsigned short n_input;
       Animal Pet;

       cout << "Name? ";
       cin >> s_input;
       Pet.SetName(s_input);

       cout << "Species? ";
       cin >> s_input;
       Pet.SetSpecies(s_input);
      
       cout << "Does your pet male? ( 1 - Yes or 0 - No ): ";
       cin >> n_input;
       if (n_input == 1) Pet.SetGender(true); else Pet.SetGender(false);

       cout << "Age? ";
       cin >> n_input;
       Pet.SetAge(n_input);

       cout << "Weight? ";
       cin >> n_input;
       Pet.SetWeight(n_input);

       cout << "Legs? ";
       cin >> n_input;
       Pet.SetLegs(n_input);

       cout << endl << Pet.GetName() << endl;
       cout << Pet.GetSpecies() << endl;
       cout << Pet.GetGender() << endl;
       cout << Pet.GetAge() << endl;
       cout << Pet.GetWeight() << endl;
       cout << Pet.GetLegs() << endl << endl;
      

       system("PAUSE");
       return 0;

}

Kad pokrenete program, vaši rezultati će biti slični:

Name? Leo
Species? Dog
Does your pet male? ( 1 - Yes or 0 - No ): 1
Age? 3
Weight? 20
Legs? 4

Leo
Dog
Male
3
20
4

Press any key to continue . . .


Šta je destruktor?

Destruktor je specijalna metoda koja oslobađa memoriju. Čisti resurse pre nego što se objekat uništi. Destruktor ima sintaksu sličnu konstruktoru osim znaka tilde ~ na početku imena destruktora. Ne može imati ulazne parametre. Klasa može imati samo jedan destruktor. U ovom primeru nema potrebe za korišćenjem destruktora, ali da smo na primer koristili pokazivače u klasi; mogli bi smo njihovu memoriju osloboditi u destruktoru; ključnom rečju delete.

delete *pokazivac;

Bilo kakva potreba za oslobađanjem memorije ili kad pišete kod za zatvaranje fajla, to radite u destruktoru. Moguće ga je i eksciplitno pozivanje destruktora ali se to ne preporučuje.

Kako celi program izgleda, možete pogledati i na video-u

 

 ( C++ Tutorial - 10. Classes ( Part II ) )