c++ programavimas

C++ programavimo kalba
Visa pagrindine teorija, klausimai ir atsakymai su pavyzdziais.

Įvadas į OOP, I/O biblioteka
Programavimo kalbos
n Procedūrinės (ankstyvos Fortran versijos)
n Pagrindą sudaro funkcijos. Programos kodo ilgis iki kelių tūkstančių eilučių.
n Struktūrinės (Pascal, C, Fortran, Basic, COBOL)
n Pagrindą sudaro blokai (procedūros) ir duomenys, priskirti tiems blokams. Programos kodo ilgis iki 50 tūkstančių eilučių.
n OOP (C++, Java, Visual Basic)
Struktūrinis programavimas
n Struktūrinio programavimo požymiai:
n Programos lengvai suprantamos, testuojamos, modifikuojamas.
n Struktūrinio programavimo taisyklės
n Naudojamos single-entry/single-exit valdymo struktūros;
n Taisyklės
1) Pradedama nuo “paprasčiausios” struktūrinės schemos;
2) Bet kuris veiksmas, gali būti pakeistas dviejų veiksmų seka;
3) Bet kuris veiksmas gali būti pakeistas valdymo sttruktūra ( if, if/else, switch, while, do/while, for)
4) 2 ir 3 punktas gali kartotis

OOP
n Išradėjai Ole-Johan Dhal ir Kristen Nygaard iš Oslo Universiteto ir Norvegijos Skaičiavimo centro (Norsk Regnesentral). OOP konsepcija buvo pristatyta 1966.

n OOP esmė – sudaryti realaus pasaulio atspindį programinio kodo struktūroje.
importantStuff = new Object( );
importantStuff.money = 500;
importantStuff.papers = 96;
importantStuff.annPassport = “er246vjl”;
importantStuff.bobPassport = “kl554mkt”;

importantStuff.jewelryBox = new Object( );
importantStuff.jewelryBox.necklace1 = “Pearl”;
importantStuff.jewelryBox.necklace2 = “Diamond”;
C++
n C++ – tai C kalbos pratęsimas, priskiriant ją OOP kalbų grupei, todėl išlieka C ir C++ suderinamumas.
n C++ geriau nei C, nes:
n Išsamesnis klaidų tikrinamas, lengvesnė klaidų paieška;
n Nuorodų (reference) panaudojimas funkcijų argumentuose irr grąžinamose reikšmėse yra patogesnis nei žymių (pointer).
n Funkcijų perkrovimas (overloading) leidžia naudoti tuos pačius f-jų pavadinimus skirtingoms funkcijoms.
n Vardų erdvės (namespace) leidžia geriau kontroliuoti vardų naudojimą
C++ privalumai prieš C
n ~10 % didesnis programų našumas nei C;
n Programos (didelės) lengviau taisomos bei modifikuojamos;
n Dėl klasių pr

ritaikymo lengviau naudojamos bibliotekos
n Šablonai (template) automatiškai modifikuoja programinį kodą, taip palengvinami bibliotekų naudojimą;
n Progaminis kodas gali viršyti 50.000 eilučių;

I/O biblioteka
n I/O srautas – tai loginis įrenginys informacijos gavimui iš vartotojo ir informacijos perdavimui vartotojui.
n I/O srautas siejamas su fiziniais įrenginais (ekranu, klaviatūra, pele, HDD) per C++ I/O sistemą t.y. I/O biblioteką, vadinamą iostream.
n Tokia I/O sistema užtikrina vieningą trarką informacijos įvedimui/išvedimui.
n I/O biblioteka suskirstyta į 4 failus:
1. iostream.h
2. fstream.h
3. strstream.h
4. iomanip.h
iostream
Header File Description
iostream.h Defines a hierarchy of classes for low-level (untyped character-level) IO and high-level (typed) IO. This includes the definition of the ios, istream, ostream, and iostream classes.
fstream.h Derives a set of classes from those defined in iostream.h for file IO. This includes the definition of the ifstream, ofstream, and fstream classes.
strstream.h Derives a set of classes from those defined in iostream.h foor IO with respect to character arrays. This includes the definition of the istrstream, ostrstream, and strstream classes.
iomanip.h Defines a set of manipulator which operate on streams to produce useful effects.

Form of I/O Input Output Input and Output
Standard I/O istream ostream iostream
File I/O ifstream ofstream fstream
Array of char I/O istrstream ostrstream strstream
Apibrėžti standartiniai srautai
Stream Type Buffered Description
cin istream Yes Connected to standard input (e.g., the keyboard)
cout ostream Yes Connected to standard output (e.g., the monitor)
clog ostream Yes Connected to standard error (e.g., the monitor)
cerr ostream No Connected to standard error (e.g., the monitor)
I/O operatoriai
n Įvedimo <<
n Išvedimo >>

#include
void main()
{
float A = 18.236;
cout << “1. A=” << A << endl;
cout << &#

#8220;2. A=” << A*2.0 << endl;
}

I/O
n setw (n) n – lauko plotis simboliais,
n setprecision (n) n – skaitmenų skaičius.

Jei setw nurodyto lauko dydžio skaičiui nepakanka, manipuliatorius ignoruojamas.
Nuoroda setw galioja artimiausiai išvedamai reikšmei, o setprecission – iki naujo
nurodymo

#include
#include
main() {
float A = 18.236;
cout << “1. A=” << setw(9) << A << endl;
cout << “2. A=” << setprecision(3) << A << endl;
cout << “3. A=”
<< setw(10) << setprecision(5) << A <
main() {
char sim;
cout << “Ar dar dirbsite?( T/N ): “;
do {
sim = cin.get();
sim = toupper(sim); }
while((sim != ‘T’) && (sim != ‘N’));
cout << “Jus pasirinkote : ” << sim << endl;
}

Įvedimo klasėje metodas getline skirtas vienos eilutės įvedimui klaviatūra. Matome, kad paprastai įvedama eilutė iki pirmojo tarpo simbolio arba iki galo, jeigu tarpo simbolio nebuvo. Panaudoję getline metodą galima įvesti norimą simbolių skaičių: nurodomas skaičius. Jeigu tiek simbolių nebuvo, įvedami visi simboliai iki eilutės galo. Įvedama eilutė visuomet papildoma nuliniu simboliu.

main() {
char A[30];
int n;
cout << “Iveskite eilute:n”;
cin >> A; // Pirmasis eilutės žodis
cout << “Eilute: *” << A << “*n”;
cin.getline(A, 12); //Vienuolika simbolių ir ‘’
cout << “Eilute: *” << A << “*n”;
cin.getline(A, sizeof(A)); // Iki galo arba tiek, kiek telpa
cout << “Eilute: *” << A << “*n”;
n = cin.gcount(); // Eilutės ilgis su nuliniu simboliu
cout << “n= ” << n << endl;
}

I/O biblioteka

(2 paskaita)

I/O operatoriai
n Išvedimo <<
n Įvedimo >>

#include
void main()
{
float A = 18.236;
cout << “1. A=” << A << endl;
cout &l

lt;< “2. A=” << A*2.0 << endl;

}
I/O
n setw (n) n – lauko plotis simboliais,
n setprecision (n) n – skaitmenų skaičius.

Jei setw nurodyto lauko dydžio skaičiui nepakanka, manipuliatorius ignoruojamas.
setw galioja artimiausiai išvedamai reikšmei, o setprecission – iki naujo nurodymo

#include
#include
void main() {
float A = 18.236;
cout << “1. A=” << setw(9) << A << endl;
cout << “2. A=” << setprecision(3) << A << endl;
cout << “3. A=“ << setw(10) << setprecision(5) << A <
void main() {
char sim;
cout << “Ar dar dirbsite?( T/N ): “;
do {
sim = cin.get();
sim = toupper(sim); }
while((sim != ‘T’) && (sim != ‘N’));
cout << “Jus pasirinkote : ” << sim << endl;
}
Įvedimo klasėje metodas getline() skirtas vienos eilutės įvedimui klaviatūra.
getline( char* pch, int nCount, char delim = ‘n’ );

Matome, kad paprastai įvedama eilutė iki pirmojo tarpo simbolio arba iki galo, jeigu tarpo simbolio nebuvo.

Panaudoję getline metodą galima įvesti norimą simbolių skaičių (nurododant skaičių).

Jeigu tiek simbolių nebuvo, įvedami visi simboliai iki eilutės galo.

Įvedama eilutė visuomet papildoma nuliniu simboliu.

void main() {
char A[30];
int n;
cout << “Iveskite eilute:n”;
cin >> A; // Pirmasis eilutės žodis
cout << “Eilute: *” << A << “*n”;
cin.getline(A, 12); //Vienuolika simbolių ir ‘’
cout << “Eilute: *” << A << “*n”;
cin.getline(A, sizeof(A)); // Iki galo arba tiek, kiek telpa
cout << “Eilute: *” << A << “*n”;
n = cin.gcount(); // Eilutės ilgis su nuliniu simboliu
cout << “n= ” << n << endl;
}

Įvedimo klasėje metodas ge

etline() gali turėti trečią parametrą,
nurodantį simbolį, kuriuo baigiamas įvedimas. Pavyzdyje parašyta
raidė ‘Z’. Jeigu įvedamoje eilutėje jos nebus, tuomet bus įvedami visi
eilutės simboliai arba tik tiek, kiek nurodyta, jeigu eilutėje jų yra daugiau.

main() {
char A[30];
cout << “Iveskite eilute:n”;
cin.getline(A, sizeof(A), ‘Z’);
cout << “Eilute: *” << A << “*n”;
}

ifstream, ofstream
Įvedimo srautu iš failo klasė ifstream ir išvedimo srautu į failą klasė
ofstream aprašytos faile fstream.h. Tai išvestinės klasės iš istream ir ostream.

Galima sukurti objektus, kurie nukreipia įvedimoišvedimo srautus išį failus.
Jiems atitinkamai galioja operatoriai >> ir <<.
Konstruktoriaus parametru yra failo vardas. Failo uždarymui naudojamas metodas
close().

#include
#include
main() {
ofstream ofs (“Rez58.txt”);
ifstream ifs (“Duom58.txt”);
int A;
ifs >> A;
cout << ” A= ” << A << endl;
ofs << A;
ofs.close(); ifs.close();
}

Failų atidarymo rėžimai
Rėžimas Aprašymas
ios::in Failas atidaromas skaitymui
ios::out Failas atidaromas rašymui
ios::ate Failas atidaromas rašymui, išvedimas pradedamas nuo failo galo (at end)
ios::app Failas atidaromas papildymui
ios::trunc Naikinamas failo turinys
ios::binary Failas atidaromas dvejatainiame režime

Pavyzdžiai
n ifstream (const char *name, ios::openmode = ios::in);
n ofstream (const char *name, ios::openmode = ios::out | ios::trunc);
n fstream (const char *name, ios::openmode = ios::in | ios::out);
fstream fs(“File.dat”);

ofstream fs;
fs.open(“File.dat”, ios::app);

if ( ! fs )
cout<< “Failo nepavyko atidaryti”<> A; ?
cout << A << endl;
R << A << endl;
}
D.close(); R.close();
}

istream::get ifstream’e
#include
#include
main() {
ofstream R(“Rez511.txt”);
ifstream D(“Duom511.txt”);
char sim;

while(!D.eof()) {
sim = D.get(); // get() naudojamas, kaip istream
cout << sim;
R << sim; }
D.close();
R.close();
}

ios.fail()
Kiekvienu skaitymo iš failo žingsniu būtina patikrinti, ar veiksmas buvo sėkmingai atliktas.

Tam skirtas metodas fail(), kurio rezultatas yra 0, kai klaidų nebuvo, ir 1, kuomet įvyko klaida.

Klaidų pranešimams ekrane skirtas išvedimo srautu objektas cerr.

Metodas fail() naudojamas išvedime, norint įsitikinti, ar veiksmas buvo sėkmingas.

#include
#include
main(){
ofstream R (“Rez512.txt”);
ifstream D (“Duom512.txt”);
int a;
if ( D.fail() ) cerr << “Neatidarytas duomenu failas”;
else {
while((!D.eof()) && (!D.fail())) {
D >> a;
if( ! D.fail() ) {
R << a << endl;
cout << a << endl; }
}
}
D.close();
R.close();
}

ostream::write istream::read
Šiose klasėse yra write ir read metodai, skirti duomenų
mainams su failais baitų lygyje.

n write( const char* pointer, int nCount );
n read ( char* pointer, int nCount );

Struktūros

(3 paskaita)

Struktūros
Visi kintamieji, iki šiol kuriais naudojotės, priklausė baziniams
C/C++ duomenų tipams:
q Sveiko tipo (int) kintamieji ir konstantos;
q Realaus tipo (float) kintamieji ir konstantos;
q Dvigubo tikslumo (double) kintamieji ir konstantos;
q Simbolinio tipo (char) kintamieji ir konstantos;
Šie duomenys galėjo sudaryti masyvus, tačiau masyvo ele-
mentais gali būti tik to paties bazinio tipo duomenys.

Struktūra – tai vienodo arba skirtingo tipo kintamųjų rinkinys.
Struktūra priklauso išvestinių (vartotojo) duomenų tipui.

Struktūra realiame pasaulyje
n Sąrašai
q Įmonės darbuotojai
n Vardas, pavardė, adresas, gim.metai, išsilavinimas, paso Nr.
q Telefono numerių
n Vardas, pavardė, adresas, tel.Nr.
n Kartotekos
q Knygų, prekių, CD .

Struktūra realiame pasaulyje
Elementas D. tipas Ilgis (eilutės) Komentaras
ID char * 4 Kodas
name char * 20 Pavadinimas
description char * 40 Aprašymas
category int 12 Kategorija
cost float Kaina
number int Kiekis

Struktūros sintaksė
struct NAME
{

type1 var1;

type2 var2;

..

typeN varN;
} ; // ; būtinas!!!!

struct CD

{
char name[20];

char description[40];

char category[12];

float cost;

int number;

} ;

Struktūrinis objektas
struct CD

{

char id[4];

char name[20];

char description[40];

char category[12];

float cost;

int number;

} disc;

CD disc, cdrom;
CD disc[10],cdrom [100];
CD *pointer;

struct CD disc; // C kalbos sintaksė

Struktūros elementų inicializacija
struct CD

{

char id[4];

char name[20];

char description[40];

char category[12];

float cost;

int number;

} disc = {“p12”, “Aliukai”,“Best Hists”,”pop-muzika”,

12.20, 12};

CD disc={“p12”, “Aliukai”,“Best Hists”,”pop-muzika”, 12.20, 12};

Struktūros elementų pasiekimas
Kreipiantis į struktūrų elementus vartojami sudėtiniai vardai:
Struktūros_objekto_vardas.lauko_vardas

disc.cost=10.12;
disc.number=9;
strcpy(disc.id, “p12”);
strcpy(disc.name, “Aliukai”);
strcpy(disc.description, “Best Hits”);
// kitas variantas

cout<<“ Iveskite kieki : “; cin >>disc.number;

cout<<“ Iveskite ID : “; cin.getline(disc.id, sizeof(disc.id));

Bitiniai laukai
Siekiant taupyti atmintį, struktūros elementams gali būti priskirti bitiniai laukai. Sintaksė:
Lauko_deklaravimas : konstanta;

struct DATE
{

unsigned short Year;

unsigned short Month;

unsigned short Day;
}

struct DATE
{
unsigned Year : 12;
unsigned Month : 4;
unsigned Day : 5;
}

Struktūros – funkcijų argumentai
struct CD

{

char id[4];

char name[20];

char description[40];

char category[12];

float cost;

int number;

}

void func(CD); – funkcijos prototipas, kai struktūra argumentų sąraše
CD func1(СD); – funkcijos prototipas, kai struktūra argumentų sąraše ir grąžinama struktūra.

struct CD

{

char name[20];

char description[40];

char category[12];

float cost;

int number;

} disc, getdisc();
void main()

{

disc=getdisc();

cout<”.

struct telefonas
{ char vardas[30];

unsigned long tel_nr;

};

struct telefonas Tel, *P, TelMas[100];
P = &Tel;
cout << P->tel_nr, Tel.vardas, P->vardas;

Junginiai (union)
Junginiai (union) tai tam tikros struktūros, kurios naudojamos tuomet, kai norima toje pačioje atminties srityje patalpinti skirtingo tipo duomenis. Tam tikru laiko momentu atmintyje gali būti tik vienas iš apibrėžtų duomenų elementų.
union Mydata
{int var1;

unsigned long frequency;

char Symb[10];
} myX = 25; // Reikšmė 25 priskiriama var1

Direktyvos, klasės

(4 paskaita)

Direktyvos
Priešprocesoriaus direktyvos – tai komandos kompiliatoriui, kurios leidžia
valdyti kompiliavimo procesą. Visos direktyvos pradedamos ženklu #.
Direktyvos apdorojamos pirminiame programos kompiliavimo etape.

#include \ paieška include
#include “header_name” \ paieška . po to include
#include macro \ makro komandos prijungimas

#include
#include “def.h”
#include MACRO(x) ( (x)*(x) )

#define #undef
Direktyva #define leidžia apibrėžti identifikatorių, o #undef jį naikina.

#define _cplusplus \ apibrėžia identifikatorių arba simbolinę konstantą
#define WIDTH 80
#define LENGTH ( WIDTH + 10 ) \ LENGHT = 90
.
.
#undef WIDTH
#undef LENGTH

#ifdef #ifndef
Direktyvos #ifdef ir #ifndef tikrina ar identifikatorius yra/nėra
apibrėžtas. Jis veikia kaip sąlygos operatorius, todėl
užbaigiamas #endif direktyva.

#ifndef test
#define final
#endif

#if, #elif, #else, #endif
#if direktyva kartus su #elif, #else ir #endif direktyvomis, kontroliuoja kompiliavimą tam tikrų programos dalių. Jei išraiška, kuri parašyta po #if turi nenulinę reikšmę, eilučių grupė, einanti tuoj pat po #if direktyvos siunčiama transliavimo vienetui.
#if defined(CREDIT)

credit();
#elif defined(DEBIT)

debit();
#else

printerror();
#endif

#if DLEVEL > 5

#define SIGNAL 1
#if STACKUSE == 1

#define STACK 200
#else

#define STACK 100
#endif
#else

#define SIGNAL 0
#if STACKUSE == 1

#define STACK 100
#else

#define STACK 50
#endif
#endif

Direktyvų panaudojimo pavyzdys
// EXAMPLE.H – header file

#if !defined( EXAMPLE_H )
#define EXAMPLE_H
class Example { . };
.
.
#endif

Macros
Macros – tai programinio kodo fragmentas, kuris atrodo ir elgiasi kaip funkcija, tačiau egzistuoja tokie skirtumai:

q Macros naudojamas priešprocesoriuje, prieš pradedant kompiliavimą
q Macros dirba greičiau nei funkcija, nors ir padidina programos ilgį.
q Macros’e netikrinami kintamųjų tipai
q Neįmanoma nustatyti nuorodą į macros, nes tai programos dalis
Macros pavyzdys
#include
#define MULTIPY(x,y) ((x)*(y))

int main()
{ int a=2, b=3;

cout<< “Sandauga ”<
char *Date = __DATE__;
char *Time = __TIME__;

int main()
{
cout<<“Failo sukurimo data ”<
using namespace std;
class small {

private: int somedata;

public: void setdata(int d)
{somedata = d; }

void showdata()
{cout<<“Duomenys “< }

Pavyzdys
int AnyClass::get_a()
{return a;
}

void AnyClass::set_a(int num)
{a = num;
}

Klasės elementų požymiai
Klasės elementai (duomenys ir metodai) gali turėti požymius. Požymis klasėje galioja tol, kol bus sutiktas kito požymio užrašas.
Jeigu požymio užrašo nėra, tuomet pagal nutylėjimą bus priimtas private visiems elementams iki pirmojo požymio užrašo, jeigu jis bus.
Yra tokie požymiai:
n private (lokalusis). Duomenys ir metodai prieinami tik klasės metodams.
n public (globalusis). Klasės elementai prieinami tiek klasės funkcijoms tiek ir išorinėms funkcijoms.
n protected (apsaugotasis). Klasės elementai prienami klasėje, kuri paveldi duotąją klasę. Paveldėtoje klasėje jie galioja private teisėmis

Palyginimas
Savybės Klasės Struktūros Junginiai
Raktinis žodis class struct Union
Priėjimas prie duo-menų (default) private public Public
Duomenų perdengimas ne ne taip
Klasės savybės
n Klasės duomenų apribojimai:
q Klasės duomenys negali būti apibrėžiami, naudojant modifikatorius auto, extern ir register;
q Klasės duomenų tarpe negali būti tos pačios klasės objektas, tačiau gali būti nuoroda į objektą ar kitos klasės objektas.
n Paprastai duomenys būna private, o funkcijos public.
n Klasė formuoja savo vardų erdvę, todėl kreiptis į kintamąjį iš kitos klasės galima naudojant tokią sintaksę:

klasės_vardas::kintamojo_ar_funkcijos vardas
Pavyzdys
#include
// Klasės aprašymas
class Studentas {

char *pav;

float svoris;
public:

void Skaito() {
cout << “Iveskite pavarde: n”;
cin >> pav;
cout << “Iveskite svori:n”;
cin >> svoris; };
void Rodo() {
cout << pav << ” ” << svoris << endl; };
};

// Pagrindinė programa
void main()
{
Studentas A, B; A.Skaito();
B.Skaito();
B.Rodo();
A.Rodo();
}

Konstruktorius, destruktorius,

draugiškos funkcijos

(5 paskaita)
Konstruktorius
Sukuriant objektą, jo duomenims paprastai priskiriamos pradinės reikšmės. Tai gali atlikti tam skirti metodai. Bet būtų patogu, jei kuriant objektą, duomenų inicializacija būtų atliekama automatiškai, neiškviečiant papildomų funkcijų. Tai galima atlikti naudojant specialų metodą – konstruktorių.

Konstruktorius – tai metodas, kuris automatiškai vykdomas kiekvieną kartą, kai tik sukuriamas objektas.

Konstruktorius turi tokį pat pavadinimą, kaip ir klasė bei nieko negrąžina. Jo paskirtis – priskirti pradines reikšmes klasės kintamiesiems.
#include
class studentas
{ float svoris;
public:

studentas(float x)

{ svoris = x; }

void rodo()

{ cout << svoris << endl; }
};
void main()
{ studentas Algis(120.25);

studentas Jonas(56.2);

cout<<“Algio svoris “<
class Counter
{ unsigned int count;
public:

count()

{ count = 0; }

void increase()

{ cout ++ ; }

int show()

{ return count; }
};

void main()
{ Counter C1;

cout<<“Skaitliukas = “<<

C1.show() << endl;
C1.increase();
cout <<“Skaitliukas =“ <<

C1.show()<
class Any
{ int a, b;
public:

Any(int x, int y)

{ a = x;

b = y; }

void show_x()

{ cout << x< Obj.name(&Obj, par1, par2);

Obj::name(param1, param2)

{ cout<<“Hello”<param1<>ilgis>>plotis;}
};

Objektų masyvai
Objektai kaip ir paprasti kintamieji gali sudaryti masyvus. Sintaksė niekuo nesiskiria nuo įpratinės masyvų apibrėžimo sintaksės.
AnyClass ACDC[10];
Kompiliatorius kurdamas masyvą, naudoja konstruktorių pagal nutylėjimą, todėl rekomenduojama klasėje apibrėžti tokį konstrukorių. Masyvų elementai pasiekiami analogiškai, kaip ir įprastinių masyvų.

class AnyClass
{ int a;

public:
AnyClass(int x) { a = x; }
int show()
{ retunt a; }
};

main()
{ AnyClass Arr[3] = { 12, 14, 16};
for (int i = 0; i<3; i++)

cout<< Arr[i].show()<< endl;
return 0; }

class AnyClass
{ int x, y;

public:
AnyClass(int a, int b) { x=a, y=b; }
int Getx() { return x; }
int Gety() { return y; }
};

main ()
AnyClass Arr[2][2] = { AnyClass(1,2), AnyClass(2,3), AnyClass(3,4),

AnyClass(5,6)};
int i , j;
for (i = 0; i<2; i++)
for (j = 0; j<2; i++)

{ cout<< Arr[i][j].Getx()<< endl;

cout<< Arr[i][j].Gety()<< endl;}
return 0; }

class AnyClass
{ int x, y;

public:
AnyClass(int a, int b) { x=a, y=b; }
AnyClass() { x=0, y=0; } // konstruktorius pagal nutylėjimą
int Getx() { return x; }
int Gety() { return y; }
};
main ()
AnyClass * ptr;
int i ;
ptr = new AnyClass[6];
for (i = 0; i<6; i++)

{ cout<< ptr->Getx()<< endl;

cout<< ptr->Gety()<< endl;

ptr ++; }
return 0; }

Draugiškos funkcijos
C++ leidžia apeiti vieną iš pagrindinių OOP savybių t.y. duomenų inkapsuliaciją panaudojant draugiškas funkcijas ir draugiškas klases.
Paprastai uždari klasės duomenys, pasiekiami per tos pačios klasės metodus. Tačiau klasės duomenis galima pasiekti ir per išorinę draugišką funkciją.
Ta pati funkcija gali turėti priėjimą prie kelių klasių duomenų. Tokia funkcija turi būti apibrėžta klasėje su atributu friend.
class beta;
class alfa
{ int data;

public:

alfa() : data(3) { }
friend int draugas (alfa, beta) // draugiška funkcija
};
class beta
{ int data;

public:

alfa() : data(7) { }
friend int draugas (alfa, beta) // draugiška funkcija
};
int draugas (alfa a, beta b)
{ return (a.data + b.data);}
main ()

alfa aa; beta bb;

cout<< draugas(aa, bb)<< endl;

return 0; }

Draugiškos klasės, paveldėjimas

(6 paskaita)
Draugiškos funkcijos
Draugiškos funkcijos nepriklauso klasės metodams, todėl iškviečiant draugišką funkciją, nereikia prieš ją nurodyti objekto vardo ar nuorodos į objektą. Uždarus klasės duomenis draugiška funkcija pasiekia per klasės objektą, kuris turi būti apibrėžtas funkcijoje arba perduotas per funkcijos argumentų sąrašą.
Draugiška funkcija nepaveldima.
class AnyClass
{ int n, d;

public:

AnyClass (int x, int y) : n(x), d(y) { }

friend bool draugas (AnyClass) ;
};

bool draugas (AnyClass obj)
{ if (! obj.n % obj.d )

return true; return false; }

main ()

AnyClass obj (12, 3);

if (draugas(obj))

cout<< “12 dalinasi is 3”<< endl;

else

cout<< “12 nesidalina is 3”<< endl;

return 0; }

Funkcija gali būti vienos klasės metodu, o kitoje klasėje būti draugiška funkcija.
class beta; // nepilnas klasės apibrėžimas. Jis būtinas
class alfa
{ int data1, data2, ;

public: alfa() : data1(3), data2(4) { }

int draugas (beta bb)

{ return (bb.b1 + bb.b2); }
};
class beta
{ int b1, b2;

public: beta() : b1(7) b2(8) { }

friend int alfa::draugas (beta bb) // draugiška funkcija iš klasės alfa
};
void main ()

{ alfa aa; beta bb;

cout<< aa.draugas(bb)<< endl; }

Draugiška klasė
C++ leidžia apibrėžti ne tik draugiškas funkcijas, bet ir klases. Draugiškai klasei suteikiamos teisės pilnai naudoti duotosios klasės duomenimis. Tam tikslui reikia, kad klasėje A būtų skelbiama, kad klasė B yra draugiška. Tai daroma parašant atributą friend prieš klasę. Draugiška klasė skelbiama klasės dalyje public.

Taisyklės, taikomos draugiškoms klasėms:
§ Negalioja abipusės draugystės savybė t.y. jei klasė B yra draugiška

klasei A, tai nereiškia, kad klasė A draugiška klasei B.
§ Draugiškos klasės nepaveldimos. Jei klasė B yra draugiška

klasei A, tai klasėse, kurios yra gautos, kaip B išvestinės, nėra

draugiškos klasei A.
§ Draugiškumas nepaveldimas t.y. jei B yra draugiška klasei A, tai klasėse

kurios yra gautos, kaip A išvestinės, klasė B nėra draugiška.

class A
{ int n, d;

public:

A (int x, int y) { n=x; d=y; }

void increase() { n++; d = d*10; }

friend class B ;
};
class B
{ A objA;

public:

void show()

{ cout<< “Pradinės reikšmės”<
#include
// Klasė Pirmas

class Pirmas { int x;

public: Pirmas(int a) { x = a; }

void Rodo()
{ printf(“Pirmas::rodo() %5d nr”, x); }
};
// Klasė Antras

class Antras: public Pirmas { int y;

public: Antras(int b, int c) : Pirmas(5)

{ y = c; }

void Rodo(){

printf(“Antras::rodo() %5d nr”, y); }
};

main ()
{ Antras B (4, 55);

B.Rodo();

B.Pirmas::Rodo();
}

Destruktorius
Nors destruktorius nėra paveldimas, uždarinėjant išvestinės klasės objektą, vistiek įvykdomas bazinės klasės destruktorius.
Išvestinės klasės destruktorius turi būti vykdomas ankščiau nei bazinės, priešingu atveju bus sunaikinti bazinės klasės duomenys.
Destruktoriaus vykdymo eiliškumu rūpinasi kompiliatorius t.y. programuotojo tai neliečia.
class Base
{ public: Base()

{ cout << Bazinis konstruktorius<
// funkcijos abs perkrovimas
int abs (int a);
float abs (float b);
double abs (double c);
void main ()
{ int x = 255; float y = -1.2f; double z = -15.0;

cout << abs (x)<< endl;

cout << abs (y)<< endl;

cout << abs (z)<< endl;
}

int abs (int a)
{ return a<0? –a:a; }

float abs (float b)
{ return b<0? –b:b; }

Funkcijų perkrovimo apribojimai
n Perkraunamos funkcijos turi turėti skirtingus argumentų sąrašus;
n Negalimos perkrautos funkcijos, turinčios tuos pačius argumentų sąrašus ir skirtis tik grąžinamos reikšmės tipu.
n Klasės metodai nelaikomi perkrautais, jei vienas iš jų apibrėžtas kaip static, o kitas ne.
n typedef operatorius neįtakoja perkrovimo mechanizmui.

typedef char* ptr;
void SetVal (char * xx); Klaida, tai nepersidengiančios funkcijos
void SetVal (ptr xx);

Klasės metodų perkrovimo pavyzdys
class Lapas
{ int x; float y; char z;

public:

Lapas (int, float, char ) { x = A; y = B; z = C; } // Konstruktorius

Lapas() { x = 0; y = 0; z = ‘z’; } // Konstruktorius

void Rodo (char *);

void Suma (int Sk) { x = x + Sk; }

void Suma (float Sk) { y = y + Sk; }

void Suma (char Sk) { z = Sk; }

void Suma (int A, char B) { x = x + 2.0 * A; z = B + 4; }
};
void Lapas::Rodo(char *Eilute) {
cout << Eilute << ” : “;
cout << ” x= ” << x << ” y= ” << y << ” z= ” << z < Func(104); //blogai

ptr -> Func(12.2, “Eilute”)

return 0;
};

Konstruktorių perkrovimas
Dažniausiai perkrovimas naudojamas kuriant perkrautus konstruktorius. Taip yra daroma siekiant suteikti galimybę kurti objektus, naudojant skirtingus argumentų sąrašus.
Class Rect
{ private : int x,y,w,h;

public: Rect() {x=y=w=h=0; }

Rect(int a, int b); { x = a; y = b; w=h=10; }

Rect(int a, int b, int c, int d); { x = a; y = b; w = c; h=d; }

Rect(const Rect&);

Rect(const Rect&, int, int );
};
Rect::Rect(const Rect& rc)
{x=rc.x; y=rc.y;

w = rc.w; h = rc.h }

Konstruktorių perkrovimas
Rect::Rect( const Rect& rc, int _x, int _y)
{x = _x;

y = _y;

w= rc.w;

h = rc.h;}
void main ()
{ Rect rc(3,4,5,6);

Rect newrc(rc, 14, 34);
}
Kopijos konstruktorius
Kopijos konstruktorius naudojamas siekiant jau iš esamo objekto sukurti naują, kaip esamo kopiją.
Kintamųjų kopijos daromos, kai jie perduodami funkcijoms per argumentų sąrašą. Dėl tos priežasties C++ buvo sukurtas kopijos konstruktorius, kuris automatiškai generuojamas kuriant objektus.
Tokiu būdu panaudojant panaudojant tokią sintaksę:

AnyClass obj1;
Anyclass obj2(obj1);
atliekamas objekto kopijavimas.
Argumentų sąraše naudojant rodykles į objektą, turime reikalą su tuo pačiu objektu o ne jo kopija.
Perkrovimas ir nevienareikšmiškumas
Kompiliatorius funkcijas išrenka pagal geriausio atitikimo principą t.y.
1. Rasta tikslaus pavadinimo f-ja;
2. Rasta tikslių argumentų f-ja;
Jei po tokios atrankos, lieka daugiau nei viena funkcija, kompiliatorius generuoja klaidą ir perkrovimas laikomas neveinareikšmiu.
Norint valdyti perkrautų konstruktorių paiešką, C++ turi dar vieną galimybę t.y. explicit identifikatorių panaudojimą. Toks identifikatorius neleidžia konstruktoriui atlikti neištrikštinį duomenų keitimą

class T
{ public: explicit T(int);

explicit T(double);};

Perkrautos f-jos adresas
Funkcijos adresas randamas tokiu būdu: rodyklei, kurios tipas atitinka funkcijos tipą priskiriamas funkcijos, kurios adresas ieškomas be argumentų sąrašo.
Turint perkrautas funkcijas atranka atliekama pagal bendras taisykles.
Pavyzdys:
int Func(int i, int j);
int Func(long l);
int (*ptr)( int, int) = Func;
pFunc(10,20);

Operatorių perdengimas
Programavimo kalbose naudojami operatoriai pasižymi polimorfizmu
(daugiavariantiškumu). Kaip pavyzdys gali būti operatorius +, kuris
taikomas tiek int, tiek float tipo kintamiesiems, nors sudėties
veiksmai procesoriaus registruose atliekami nevienodai.
Klasėse galima naujai apibrėžti operatorius, t.y. pakeisti jų veikimą. Toks
naujas operatorių perorientavimas yra vadinamas perdengimu.
Operatorių aprašai nuo funkcijų skiriasi vartojamu žodžiu operator. Operatoriaus perdengimo sintaksė :

operator ;

Perdengimas draudžiamas operatoriams: . .* :: ?:

Operatorių perdengimas gali galioti lokaliai t.y. klasės ribose arba globaliai t.y. visoje programoje.
Operatoriai – tai funkcijos, todėl operatorių perkrovimas siejamas su funkcijų perkrovimu.
class Katinas
{ public:
Katinas(char *);
void operator + (char *);
void operator – (char );
void Rodo();
~Katinas();
private:
char *Vardas;
};

Katinas::Katinas(char *Vardas) {
Katinas::Vardas = new char[N];
strcpy(Katinas::Vardas, Vardas); }

void Katinas::Rodo()
{ cout << Vardas << endl; }
void Katinas::operator + (char * A)
{ strcat(Vardas, A); }
void Katinas::operator – (char C) {

for(int i=0; *(Vardas+i) != ‘’; ) {

if(*(Vardas + i) == C)
for(int j=i; j<(strlen(Vardas)-1); j++)
*(Vardas + j) = *(Vardas + j+1);
i++;
}}

Katinas::~Katinas()
{ delete Vardas; }

// Pagrindinė programa
void main(void) {
Katinas A (“Batuotas ir piktas”);
A.Rodo();
A + ” Rudas! “;
A.Rodo();
A – ‘a’;
A.Rodo();
getch();

Operatorių perkrovimas

(8 paskaita)
Operatorių perdengimas

Programavimo kalbose naudojami operatoriai pasižymi polimorfizmu
(daugiavariantiškumu). Kaip pavyzdys gali būti operatorius +, kuris
taikomas tiek int, tiek float tipo kintamiesiems, nors sudėties
veiksmai procesoriaus registruose atliekami nevienodai.
Klasėse galima naujai apibrėžti operatorius, t.y. pakeisti jų veikimą. Toks
naujas operatorių perorientavimas yra vadinamas perdengimu (perkrovimu).
Operatorių aprašai nuo funkcijų skiriasi vartojamu žodžiu operator. Operatoriaus perdengimo sintaksė :

[tipas] operator (parametrai);

Perdengimas draudžiamas operatoriams: . .* :: ?:

Operatorių perdengimas gali galioti lokaliai t.y. klasės ribose arba globaliai t.y. visoje programoje.
Operatoriai – tai funkcijos, todėl operatorių perkrovimas siejamas su funkcijų perkrovimu.
class Katinas
{ public:
Katinas(char *);
void operator + (char *);
void operator – (char );
void Rodo();
~Katinas();
private:
char *Vardas;
};

Katinas::Katinas(char *Vardas) {

Katinas::Vardas = new char[N];

strcpy(Katinas::Vardas, Vardas); }

void Katinas::Rodo()

{ cout << Vardas << endl; }

void Katinas::operator + (char * A)

{ strcat(Vardas, A); }

void Katinas::operator – (char C) {

for(int i=0; *(Vardas+i) != ‘’; ) {

if(*(Vardas + i) == C)

for(int j=i; j<(strlen(Vardas)-1); j++)

*(Vardas + j) = *(Vardas + j+1);

i++; }

}

Katinas::~Katinas()
{ delete Vardas; }

// Pagrindinė programa
void main(void) {
Katinas A (“Batuotas ir piktas”);
A.Rodo();
A + ” Rudas! “;
A.Rodo();
A – ‘a’;
A.Rodo();
getch();

Perdengiami operatoriai
Operatorių perdengimas – tai funkcijos operatoriai, kurių pavadinimai siejami su raktiniu žodžiu operator ir po juo einančiu operatoriumi.
Taisyklė:
Funkcijos-operatoriai turi būti nestatiniai klasės metodai arba turėti klasės tipo argumentą arba nuorodą į klasę.
Sintaksė:
Binariniai operatoriai

[tipas] operator (par1); (lokalus)

[tipas] operator (par1, par2); (globalus)
Unariniai operatoriai

[tipas] operator (); (lokalus)

[tipas] operator (par1); (globalus)
Unary: + – * ! ~ & ++ — () -> ->*

new delete
Binary: + – * / % & | ^ << >>

= += -= /= %= &= |= ^= <<= >>=

== != < > <= >= && || [] () ,

Pavyzdys (lokalus perdengimas)
class Point {
public:
Point (int x, int y) {Point::x = x; Point::y = y;}
Point operator + (Point &p) {return Point(x + p.x, y + p.y);}
Point operator – (Point &p) {return Point(x – p.x, y – p.y);}
private:
int x, y;
};

void main () {
Point p1(10,20), p2(10,20);
Point p3 = p1 + p2;
Point p4 = p1 – p2;
}

Pavyzdys (globalus perdengimas)
class Point {
public:
Point (int x, int y) {Point::x = x; Point::y = y;}
friend Point operator + (Point &p, Point &q) //globalus operatrorius
{return Point(p.x + q.x,p.y + q.y);}
friend Point operator – (Point &p, Point &q)
{return Point(p.x – q.x,p.y – q.y);}
private:
int x, y;
};

Perkrauto operatoriaus naudojimas – ekvivalentiškas funkcijos iškvietimui. Pavyzdžiui:
operator+(p1, p2); // tas pats: p1 + p2
Pavyzdys
class Point {
//.
Point (int x) { Point::x = Point::y = x; }
friend Point operator + (Point, Point);
};

Naudojamas vieno argumento konstruktorius:

Point p = 10; // equivalent to: Point p(10);

Objektai būtų kuriami taip:

Point p(10,20), q = 0;
q = p + 5; // equivalent to: q = p + Point(5);

Operatoriaus << perdengimas
Operatoriaus << perdengimas leidžia efektyviai naudoti išvedimo procedūra.

class Binary {
//.
friend ostream& operator << (ostream&, Binary&);
};
ostream& operator << (ostream &os, Binary &n)
{char str[binSize + 1];
strncpy(str, n.bits, binSize);
str[binSize] = ‘’;
cout << str;
return os;
}
Binary n1 = “01011”, n2 = “11010”;
cout << n1 << ” + ” << n1 << ” = ” << n1 + n2 << ‘n’;

Pirmas parametras – tai nuoroda į ostream, antras – nuoroda, kuri bus modifikuojama

Operatoriaus >> perdengimas
class Binary {
//.
friend istream& operator >> (istream&, Binary&);
};
istream& operator >> (istream &is, Binary &n)
{char str[binSize + 1];
cin >> str;

n = Binary(str); // use the constructor for simplicity
return is;
}
Įvedimas main() funkcijoje atrodytų:

Binary n;

cin >> n;
Pirmas parametras – tai nuoroda į istream, antras – nuoroda, kuri bus modifikuojama

[ ] perkrovimas
# Kuriamas asociatyvinis masyvas
#include
#include
class AssocVec {
public:
AssocVec (const int dim);
~AssocVec (void);
int& operator [] (const char *idx);
private:
struct VecElem {
char *index;
int value;
} *elems; // vector elements
int dim; // vector dimension
int used; // elements used so far
};

AssocVec::AssocVec (const int dim)
{
AssocVec::dim = dim;
used = 0;
elems = new VecElem[dim];
}
AssocVec::~AssocVec (void)
{
for (register i = 0; i < used; ++i)
delete elems[i].index;
delete [] elems;
}

int& AssocVec::operator [ ] (const char *idx)
{
for (register i = 0; i < used; ++i) // search existing elements
if (strcmp(idx,elems[i].index) == 0)
return elems[i].value;
if (used < dim && // create new element

(elems[used].index = new char[strlen(idx)+1]) != 0) {
strcpy(elems[used].index,idx);
elems[used].value = used + 1;
return elems[used++].value;
}
static int dummy = 0;
return dummy;}
Naudojame perkrautą [ ] taip:
AssocVec count(5);
count[“apple”] = 5;
count[“orange”] = 10;
count[“fruit”] = count[“apple”] + count[“orange”];
Atsakymas: count[“fruit”] to 15.

new ir delete perdengimas
Dinaminio atminties paskirstymo operatoriai new ir delete gali būti perkrauti klasėse. Toks perkrovimas susijęs su racionalesniu atminties panaudojimu.
#include
#include
const int maxPoints = 512;
class Point {
public:
//.
void* operator new (size_t bytes);
void operator delete (void *ptr, size_t bytes);
private:
int xVal, yVal;
static union Block {
int xy[2];
Block *next;

} *blocks; // points to our freestore
static Block *freeList; // free-list of linked blocks
static int used; // blocks used so far
};

Point::Block *Point::blocks = new Block[maxPoints];
Point::Block *Point::freeList = 0;
int Point::used = 0;

void* Point::operator new (size_t bytes)
{Block *res = freeList;
return used < maxPoints

? &(blocks[used++])

: (res == 0 ? 0
: (freeList = freeList->next, res));
}
void Point::operator delete (void *ptr, size_t bytes)
{
((Block*) ptr)->next = freeList;
freeList = (Block*) ptr;
}

Funkcijoje main() panaudojimas:

Point *pt = new Point(1,1);
// calls Point::operator new
char *str = new char[10];
// calls ::operator new
delete pt;
// calls Point::operator delete
delete str;
// calls ::operator delete

Operatorių++ ir — perdengimas
class coord
{ int x,y;
public:

coord() {x=0; y=0}

coord(int _x = x; int _y=y;}
void Getcoord(int& _x, int& _y)

{ _x=x; _y=y;}
coord& operator++();

//prefix
coord& operator++(int);
//sufix
coord& operator–();
//prefix
coord& operator–();

//sufix
};
coord& coord::operator++()
{ x++; y++;

return *this;
}

coord& coord::operator++(int)
{coord temp = *this;

++ *this;

return temp;
}
coord& coord::operator–()
{ x–; y–;

return *this;
}
coord& coord::operator–(int)
{coord temp = *this;

— *this;

return temp;
}

void main()
{ int x,y;

coord pta(10,20), ptb(15,25), ptc;

++pta;
pta.Getcoord(x,y);
cout << x << “ “<< y<< endl;
pta–;
pta.Getcoord(x,y);
cout << x << “ “<< y<< endl;
ptc = ptb++;
ptc.Getcoord(x,y);
cout << x << “ “<< y<< endl;
ptb.Getcoord(x,y);
cout << x << “ “<< y<< endl;
}

Polimorfizmas ir virtualios funkcijos

(9 paskaita)
Kam reikalingos virtualios funkcijos?
C++ virtualumas suprantamas, kaip polimorfizmo ir paveldėjimo savybių apjungimas.
Iki šiol nagrinėtos perkrautos funkcijos ar operatoriai buvo nesiejami su klasių herarchija.
Virtualios funkcijos naudojamos tuomet, kai tuo pačiu pavadinimu egzistuoja funkcijos tiek bazinėje tiek ir išvestinėse klasėse.
Virtuali – reiškia neegzistuojanti realybėje, o tai suprantama, kad kviečiant funkciją iš vienos klasės, realiai vykdoma kitoje klasėje esanti funkcija.

Pavyzdys:
shape* ptr_array [100];
// 100 rodyklių masyvas
for (int i=0; i draw( );

// ta pati funkcija draw() kviečiama iš skirtingų objektų

Problema.nr.1
BankAccount bretta;

// base-class object
Overdraft ophelia;

// derived-class object
bretta.ViewAcct();
// use BankAccount::ViewAcct() }Vienareikšmiš-kai apibrėžta
ophelia.ViewAcct();

// use Overdraft::ViewAcct() }

BankAccount bretta;
BankAccount * bp = &bretta;
// points to BankAccount object
bp->ViewAcct();
// use BankAccount::ViewAcct()
bp = &ophelia;
// BankAccount pointer to Overdraft object
bp->ViewAcct();
// which version of ViewAcc?

/atsakymas
Pagal nutylėjimą, C++ naudoja rodyklės arba nuorodos tipą, kad nuspręstų, kokią f-ją pasirinkti. Todėl bus naudojama BankAccount::ViewAcct()

Problema.nr.2
Tačiau kompiliatorius kompiliavimo metu dažnai nežino, su kokiu objektu bus surišta nuoroda ar rodyklė.
cout << “Enter 1 for Brass Account, 2 for Brass Plus Account: “;
int kind;
cin >> kind;
BankAccount * bp;
if (kind == 1)

bp = new BankAccount;
else if (kind == 2)

bp = new Overdraft;
bp->ViewAcct(); /
/ neaišku, kuri funkcija bus iškviesta

Apibrėžimai
Jei programos kompiliavimo metu, kompiliatorius pririša rodyklę ar nuorodą prie konkretaus objekto ir taip nustato, kurią iš perkrautų funkcijų naudoti, toks pririšimas vadinamas ankstyvuoju (early binding) arba statiniu (static binding). Kartais dar sakoma, jog tai statinio polimorfizmo atvejis.
// static binding
BankAccount *bp;
Overdraft ophelia;
bp = &ophelia;

// BankAccount pointer to Overdraft object
bp->ViewAcct();
// use BankAccount::ViewAcct()

Jei programos kompiliavimo metu, kompiliatorius nepririša rodyklės ar nuorodos prie konktetaus objekto ir palieka galimybę programos vykdymo metu nuspęsti, kurio objekto metodą iškviesti, toks atvejis vadinamas vėlyvuoju (late binding) arba dinaminiu pririšimu (dynamic binding). Sakoma, jog turime dinaminio polimorfizmo atvejį.

Dinaminio pririšimo (dynamic binding) aktyvizavimas
Dinaminis pririšimas aktyvizuojamas tik klasės metodams. Norint tai atlikti bazinėje funkcijoje perkrauta funkcija apibrėžiama kaip virtuali (naudojamas raktinis žodis virtual).
Jei metodas apibrėžtas kaip virtualus, jis toks išlieka visose paveldėtose (išvestinėse) klasėse.
Vienam virtualiam metodui raktinis žodis naudojamas tik vieną kartą ir tik bazinėje klasėje
Pavyzdys
// bankacct.h – a simple BankAccount class with virtual functions
#ifndef _BANKACCT_H_
#define _BANKACCT_H_

class BankAccount {
private: enum {MAX = 35};
char fullName[MAX];
long acctNum;
double balance;
public: BankAccount (const char *s = “Nullbody”, long an = -1, double bal = 0.0);
void Deposit (double amt);
virtual void Withdraw (double amt);
// virtual method
double Balance() const;
virtual void ViewAcct() const;
// virtual method
};
class Overdraft : public BankAccount {
private: double maxLoan;
double rate;
double owesBank;
public: Overdraft (const char *s = “Nullbody”, long an = -1, double bal = 0.0, double ml = 500, double r = 0.10);
Overdraft (const BankAccount & ba, double ml = 500, double r = 0.1); void ViewAcct()const;

void Withdraw(double amt);

void ResetMax(double m) { maxLoan = m; }

void ResetRate(double r) { rate = r; };

void ResetOwes() { owesBank = 0; } };
#endif
int main() {

BankAccount * baps[ASIZE];

char name[MAX];

long acctNum; double balance; int acctType;
for (int i = 0; i < ASIZE; i++) {
// su cin >> nuskaitomi name, acctNum, balance, acctType
if (acctType == 2)
baps[i] = new Overdraft(name, acctNum, balance);
else
{ baps[i] = new BankAccount(name, acctNum, balance);
if (acctType != 1)

cout << “I’ll interpret that as a 1.n”; }
}
for (i = 0; i < ASIZE; i++)

{ baps[i]->ViewAcct();

cout << endl; }

return 0; }

Kodėl naudojamos du polimorfizmo tipai?
Dinaminis polimorfizmas leidžia pakeisti klasės metodus – tai patogu kuriant didelius programinius projektus (>1000 eilučių).
Statinis polimorfizmo naudojimas duoda didesni programos vykdymo efektyvumą. Programos vykdymo metu nevykdomas funkcijų apibrėžimas iš naujo bei jų atranka, taip taupomas programos vykdymo laikas.

Taisyklės:
• Virtualios funkcijos naudojamos tose paveldimose klasėse, kur reikalingas funkcijų apibrėžimas iš naujo.
• Statinės funkcijos negali būti apibrėžtos virtualiomis.
• Virtuali funkcijos prototipas visose klasėse turi būti identiškas t.y. sutapti parametrų sąrašas bei grąžinamos reikšmės tipas.

Virtualios ir nevirtualios funkcijos pavyzdys
#include
class Base
{ public: virtual void VirtFunc()

{ cout << “Base::VirtFunc()n”; }
void show()
{cout << “Base klases funkcija n”; }
};
class Derived: public Base
{ public: void VirtFunc()
{ cout << “Derived::VirtFunc()n”; }
void show()
{ cout << Derived klases funkcija n”;}
};

void main ()
{Derived A_isvestine;

Derived *ptr_isvestine;

Base *ptr_base = &A_isvestine;

ptr_base->VirtFunc();

// virtualios funkcijos iškvietimas

ptr_base->show();
// nevirtuali funkcija

ptr_isvestine->VirtFunc();
// virtualios funkcijos iškvietimas

ptr_isvestine->show();
// nevirtuali funkcija
}

Virtualus destruktorius
Konstruktoriai negali būti virtualūs, tačiau destruktoriai gali. Kai šalinamas išvestinės klasės objektas, o destruktorius yra apibrėžtas kaip virtualus, vykdomi tiek išvestinės tiek ir bazinės klasės destruktoriai.
Priešingu atveju iškviečiamas tik išvestinės klasės destruktorius ir atmintyje lieka nepanaikinti bazinio objekto duomenys.

class Base
{ public: ~Base()
// virtual ~Base() taip turėtų būti
{cout<< “Base destroyed n”; }
};
class Derived: public Base
{public: ~Derv()

{cout<< “Derived destroyed n”; }
};

Daugybinis paveldėjimas, virtualios bazinės klasės
Siekiant išvengti dvigubo bazinės klasės įtraukimo, naudojamos virtualios bazinės klasės. Tam prieš paveldimumo identifikatorių rašomas žodis virtual.
class IndBase
{ int x;

public:

int GetX() {return x; }

void setX (int _x) { x= _x ;}

double var;
};
Class Base1: virtual public Indbase
{ .. };
Class Base2: public virtual Indbase
{ .. };

Class Derived: public Base1, public Base2
{ .. };

main ()

Derived ob;

ob.var = 5.0

ob.SetX(0);

int z = ob.GetX();
return 0; }

Abstrakčios klasės ir pure virtual funkcijos
Egzistuoja klasės, kurios nėra naudojamos objektams kurti, o tik tam, kad sudarytų reikiamą klasių herarchijos medį ir užtikrintų logišką paveldimumą. Tokios klasės vadinamos abstrakčiomis (abstarct).
Pavyzdžiui: bazinė klasė shape ir klasės trikampis, apskritimas, keturkampis ir t.t

Akstrakti klasė turi bent vieną virtualią funkciją, o tiksliau tikrą virtualią (pure virtual). Išvestinės klasės turi būtinai panaudoti abstrakčios klasės virtualias funkcijas, priešingu atveju jos taip pat tampa abstrakčiomis (dėl paveldimumo).
Tikrai virtualia funkcija vienareikšmiškai pasako, kad klasė, kuriai ji priklauso yra abstrakti ir objektas iš tokios klasės negali būti sukurtas.

Tikrai virutalios funkcijos sintakse:
virtual (argumentai) = 0;

Pure virtual funkcijos pavyzdys
class Base
{ int x;

public: Base( int xx) {x = xx;}

virtual int GetX() {return x;}

virtual void PrintX () = 0;
};
class Derived: public Base
{ public: Derv(int xx): Base (xx);

int GetX() { return 0;}

void PrintX()

{cout<< “x= “ <
void main( int argc, char *argv[ ],char **envp )

{ int count;

printf ( “nCommand-line arguments:” );

for( count = 0; count < argc; count++ )

printf( ” argv[%d] %sn”, count, argv[count] );

printf( “nEnvironment variables:” );

while ( *envp != NULL )

printf( ” %sn”, *(envp++) );
return;}
Command-line arguments: argv[0] C:MSCTEST.EXE
Environment variables: COMSPEC=C:NTSYSTEM32CMD.EXE PATH=c:nt;c:binb;c:binr;c:ntsystem32;c:word;c:help
TEMP=c:tmp
TMP=c:tmp

Laiko skaičiavimas, naudojant time.h
/* DIFFTIME.C: This program calculates the amount of time * needed to do a floating-point multiply 10 million times. */
#include
#include
#include
void main( void )
{ time_t start, finish;

long loop;

double result, elapsed_time;

printf( “Multiplying 2 floating point numbers 10 million times.n” );

time( &start );

for( loop = 0; loop < 10000000; loop++ )

result = 3.63 * 5.27;

time( &finish );

elapsed_time = difftime( finish, start );

printf( “nProgram takes %6.0f seconds.n”, elapsed_time );
}
time_t structure contains the number of seconds since 00:00:00 UTC, January 1, 1970

Laiko skaičiavimas su MFC
#include
CTime startTime = CTime::GetCurrentTime();
// . perform time-consuming task .
CTime endTime = CTime::GetCurrentTime();
CTimeSpan elapsedTime = endTime – startTime;

Ctime – MFC klasė
CTimeSpan – MFC klasė

Kodėl šablonai (templates)
n Šablonai leidžia sukurti bendro pobūdžio funkcijas ir klases, neprisirišant prie konkrečių duomenų tipų.
n Leidžia kurti bendro tipo bibliotekas (STL) ir taip užtikrina daugkartinį funkcijų ar klasių panaudojimą.
n Šablonų tipai : funkcijų, klasių
Pavyzdys:
int abs (int n)
{return (n<0) ? –n : n;
}
C kalboje egzistuoja fabs(), fabsl (), labs(), cabs().

Funkcijų šablonai (function template)
Funkcijos šablonas visad apibrėžiamas raktiniu žodžiu template ir vienu ar keliais prametrais .

template Max (T, T);

template T abs(T n)
{return (n<0)? –n, n;
}

Argumentai, esantys <> viduje vadinami šablono argumentais. class – raktinis žodis. Jis būtinas prieš kiekvieną argumentą.

Kompiliatorius kuria konkrečią funkcijos realizaciją (šabloninę funkciją – template function) programos vykdymo metu.
Kaip atrodys konkreti funkcija, priklauso nuo argumentų tipo.

Funkcijų šablonai su keletu argumentų
template
T3 Relation(T1, T2);
// ok
template
int Compare (T1, T1);
// illegal! T2 not used.
template
// illegal! class missing for T2
int Compare (T1, T2);

Pavyzdžiui
template
T Max (T val1, T val2)
{return val1 > val2 ? val1 : val2;
}
cout << Max(19, 5) << ‘ ‘ << Max(10.5, 20.3) << ‘ ‘ << Max(‘a’,’b’) << ‘n’

Pavyzdys
template
int find(atype* array, atype value, btype size)
{for (btype j=0; j
class pavadinimas { }
template
class Stack

{ private: Type st[10];

int top;

public: Stack() {top = -1;}

void push (Type var) { st[++top] = var; }

Type pop () { return st [top–]; }

};

void main()
{Stack s1;
s1.push(11.1F);
cout< s2;
s2.push(123L);
cout<
class Stack {
public:
Stack (int max) : stack(new Type[max]), top(-1), maxSize(max) { }
~Stack (void) {delete [ ] stack;}
void Push (Type &val);
void Pop (void) {if (top >= 0) –top;}
Type& Top (void) {return stack[top];}
friend ostream& operator << (ostream&, Stack&);
private:
Type *stack;
// stack array
int top; /
/ index of top stack entry
const int maxSize;
// max size of stack
};

Jei klasės funkcija apibrėžiama už klasės ribų naudojama sekanti sintaksė

template
void Stack::Push (Type &val)
{if (top+1 < maxSize)
stack[++top] = val;
}

template
ostream& operator << (ostream& os, Stack& s)
{for (register i = 0; i <= s.top; ++i)
os << s.stack[i] << ” “;
return os;
}
Šablonai, standartinė šablonų biblioteka (STL)

(11paskaita)
Klasių šablonai
#include
using namespace std;
template
class Stack

{ private: Type st [10];

int top;

public: Stack() { top = -1; }
// Konstruktorius

void push (Type var) { st [ ++top ] = var; }

Type pop () { return st [top — ]; }

};

void main()

{ Stack s1;

// s1 – klasės Stack objektas

s1.push(11.1F); s1.push(22.2F);

cout< s2;

s2.push(123L);
cout< keičiamas konkrečiu duomenų tipu.

Stack s1(10);
// stack of integers
Stack s2(10);
// stack of doubles
Stack s3(10);
// stack of floats

Nontype Parametrai
Klasių šablonai gali turėti ne vien tik neapibrėžto duomenų tipo kintamuosius. Ten gali būti ir kintamieji, kurių tipas iš karto apibrėžiamas.

template
class Stack {
public: Stack (void) : stack(new Type[maxSize]), top(-1) { }
~Stack (void) { delete [ ] stack; }
void Push (Type &val);
void Pop (void) { if (top >= 0) –top; }
Type &Top (void){ return stack [top]; }
private:
Type *stack;
// stack array
int top;
// index of top stack entry };

Stack s1;
// ok
Stack s2;
// illegal! 10u doesn’t match int
Stack s3;
// ok
int n = 10;
Stack s4;
// illegal! n is a run-time value
Klasių šablonų nariai (Class Template Members)
Klasių šablonų nariai gali būti konstantos, reference, static nariai t.y. tokie pat kintamieji, kaip ir įprastinėse klasėse. Jei šablone yra statiniai kintamieji, kiekviena klasė, sukurta pagal tokį šabloną turi savo statinius kintamuosius.
template
class Stack {
public: //.
Type& Top(void);
private:
//.
static Type dummy;
// dummy entry};
template
Type& Stack::Top (void)
{ return top >= 0 ? Stack [top] : dummy; }

template Type Stack::dummy = 0;

Klasių šablonai ir draugiškos klasės(funkcijos)
Klasių šablonuose gali būti draugiškos klasės ir funkcijos. Sakykime, kad turime draugišką funkcijos šabloną Foo ir draugišką klasės šabloną Stack.

template
class Sample {
// one-to-many friendship
friend Foo;
friend Stack;
};
template
class Sample {
// one-to-one friendship
friend Foo;
friend Stack;
};
template
class Sample {

// many-to-many friendship

template friend Foo;

template friend class Stack;
};

Klasių šablonai ir paveldimumas
Klasių šablonai gali būti tiek bazinėmis klasėmis tiek ir išvestinėmis klasėmis.

template
class SmartList : public List;
// bazinė klasė šablonas

class X;
template class Y : X;
// išvestinė klasė šablonas

template
class Set : public List
{
public: virtual void Insert (const Type &val)

{ if (!Member(val)) List::Insert(val); }
};

Šablonų apibendrinimas
n Šablonai – tai C++ savybė, leidžianti kurti parametrizuoto tipo funkcijas ir klases, kurių pagalba galima kurti klases ar funkcijas keičiančias savo elgseną priklausomai nuo parametrų. Šablonai – tai galimybė pakartotinai naudoti jau sukurtus programinius kodus.
n Šablonus apibrėžia parametrizuoti kintamieji.
n Klasių šablonai gali turėti draugiškas klases ir funkcijas bei klasių ir funkcijų šablonus.
n Šablonai gali turėti ir statinius kintamuosius. Tuo atveju kiekviena šablono konkretizacija kuria atskirus savo statinių duomenų rinkinius.

Standartinė šablonų biblioteka (STL)
n STL – tai konteinerinių klasių (vektoriai, sąrašai, eilės, stekai) ir bendro pobūdžio algoritmų (rūšiavimo, paieškos, kopijavimo) biblioteka.
n STL įtraukta į C++ standartą ir platinama nemokamai.
n STL tikslas – neišradinėti dviračio ir naudotis jau sukurtais ir patikimai veikiančiais klasių bei funkcijų šablonais.
n STL sudaro:
q Konteineriai – tai būdas, kaip duomenys yra saugomi atmintyje. Duomenys gali būti tipiniai (int, float.) arba objektai;
n Nuoseklūs konteineiriai
n Asociatyviniai konteineriai
q Algoritmai – tai procedūros (funkcijos), kurios taikomos konteinerio duomenų apdorojimui. Šios funkcijos nepriklauso klasėms;
q Iteratoriai – tai apibendrintos rodyklės, jungiančios algoritmus ir konteinerių elementus. Didinant ar mažinant iteratoriaus reikšmę, pasiekiamas vis kitas konteinerio elementas.
Konteineriai
Konteineriai – tai alternatyva masyvams. Konteinerių privalumas – didesnis duomenų apdorojimo greitis. Masyvais C++ laikomas duomenų saugojimo būdas, kai jo elementų skaičius apibrėžiamas iš anksto. Pvz. A[10]
STL apibrėžia 7 konteinerių tipus, kurie skirstomi į dvi kategorijas: nuoseklūs ir asociatyviniai.
Nuoseklūs konteineriai:
• vektoriai (vector)
• sąrašai (list)
• dekai (deque)
• stekai (stack)
• eilės (queue)
• prioritetinės eilės (priority_queue)

Nuoseklūs konteineriai (vektoriai)
Nuosekliuose konteineriuose saugomi duomenys gali būti įsivaizuojami kaip pvz. linija namų gatvėje. Visi elementai turi savo poziciją bei kaimynus.
Vektoriai – tai konteinerinė klasė, kurios elementai pasiekiami pagal indeksą. Vektoriai panašūs į vienmačius masyvus, tačiau jie yra dinaminiai bei užtikrina indeksų kontrolę.
Vektorių klasė apibrėžta antraštės faile vector.h ir naudoja std vardų erdvę.
#include
#include
using namespace std;
void main()
{ vector v;
// sudaromas nulinio ilgio vektorius

for (int i = 0; i<5; i++)

v.push_back(i);
// papildomas vektorius elementu, vektoriaus gale

cout<<“Vektoriaus dydis”< v1 (arr, arr+4) ;
// sudaromas vektorius

while ( !v1.empty () )

{ cout<< v1.back() <
#include
using namespace std;
void main()
{ list ilist;

ilist.push_back(30);

// elementai talpinami sąrašo gale

ilist.push_back(40);

ilist.push_front(20);
// elementai talpinami sąrašo priekyje

ilist.push_front(10);

ilist.push_front (10);

ilist.unique()
// pašalina dublikuotus elementus

ilist.reverse()
// sukeičia eiliškumą t.y. 40, 30, 20, 10

cout<<“Saraso dydis”< deq;

deq.push_back(30);
// elementai talpinami deko gale

deq.push_back(40);

deq.push_front(20);

deq.push_front(10);

deq[2] = 33;
// trečias deko elementas 33
for (int i=0; i < deq.size(); i++)

{ cout<< deq[ ] < > aStack;
stack stackOne;
// sukuriamas stekas iš sąrašo konteinerio
stack< Customer, list > custom_stack

Eilės
Eilės – taip pat viena iš populiariausių duomenų struktūrų. Duomenys organizuojami pagal principą FIFO (first in, first out), tai reiškia, kad nauji elementai pridedami iš vieno galo (uodegos), o šalinami iš kito galo (pradžios). Kaip ir stekai, eilės – tai bazinių konteinerių modifikatoriai. Eilės bazinis konteineris pagal nulylėjimą – dekas.
STL apibrėžta šabloninė klasė queue. Jos pajungimui reikalingas antraštės failas queue.h

// sukuriama eilė iš deko konteinerio
queue queueTwo;
// sukuriama eilė iš sąrašo konteinerio
queue > queueOne;
queue > queueThree;

Pavyzdys
#include
#include
#include
#include
#include
using namespace std;
int main ()
{queue q; // sudaroma eilė

q.push(1); q.push(2); // pildoma elementais

cout<< q.front() << endl;

q.pop(); // šalinamas pirmas elementas

cout<< q.front() << endl;

q.pop();
return 0; }

Iteratoriai
Iteratoriai – tai rodyklių (pointer) vaidmenį atliekantys objektai, kurių pagalba galima pasiekti tam tikrą konteinerio elementą. Dažnai jie naudojami tam, kad nuosekliai (iteratyviai) prisirišti prie vis kito elemento, tai reiškia, kad iteratorių paskirtis surišti konteinerius ir algoritmus.
STL iteratoriams sukurti naudojama klasė iterator.
Naudojami trijų pagrindinių klasių iteratoriai:
§ Judantys į priekį (forward)
§ Judantys abiejomis kryptimis (bidirectional)
§ Atsitiktiniai (random)
Specializuoti iteratoriai darbui su I/O:
§ Įvedimo (rodo į įvedimo įrenginį t.y. cin arba failas)
§ Išvedimo (rodo į išvedimo įrenginį t.y. cout arba failas)
Konteinerio elemento reikšmė gaunama naudojant * simbolį, pvz. value =*iter;

Vector List Deque Set Multiset Map Multimap
Random X X
Bidirectional X X X X X X X
Forward X X X X X X X
Input X X X X X X X
Output X X X X X X X
Algoritmai taip pat reikalauja tam tikro iteratoriaus tipo, todėl turi būti išlaikytas iteratoriaus suderinamumas iš vienos pusės su algoritmu iš kitos pusės su konteineriu.
Aukštesnio lygio iteratorius tinka algoritmui, reikalaujančiam žemesnio lygio iteratoriaus.
list iList;
list ::iterator iter;
#include
#include
#include
void main()
{int arr[ ] = {2, 3, 4, 5};

list theList;

for (int k=0; k<4; k++)

theList.push_back ( arr[k] ); // užpildomas sąrašas elementais
list::iterator iter;
for (iter = theList.begin(); iter != theList.end(); iter++)
cout<< *iter << ‘ ‘; }

Algoritmai
SLT saugoma apie 60 universalių algoritmų, kurie atlieka rutinines operacijas su duomenimis.
Jie apibrėžti antraštės faile ir naudoja standartinę vardų erdvę std.
Pavyzdys:
#include
#include
using namespace std;
int arr[ ] = {11, 22, 33, 44, 55, 66,77 };
void main()
{int *ptr;

ptr = find( arr, arr+8; 33); // rasti pirma 33

cout<<“Pirmasis 33” << (ptr- arr);
}

Asociatyviniai konteineriai
Asociatyviniuose konteineiriuose elementai siejami su raktais, kurie atlieka indekso funkcijas. Raktais dažniausiai būna skaičiai arba eilutės.
STL apibrėžia dvi pagrindines asociatyvinių konteinerių grupes:
§ set (aibė)
§ map (žemėlapis)
Aibėse saugomi unikalūs raktai, žemėlapiuose – raktų ir reikšmių poros.
Aibėse ir žemėlapiuose raktai unikalūs, tačiau multiaibėse bei multižemėlapiuose raktai gali kartotis.

Norint naudoti asociatyvinius konteinerius, reikia prisijungti antraštės failus map.h arba set.h

Aibės
Aibės dažnai naudojamos vartotojo sukurtų objektų saugojimui. Pvz. darbuotojų duomenų bazė. Tačiau aibės gali saugoti ir paprastesnius elementus – eilutes.
#include
#include
#include

void main()
{ string names [ ] = {“Jonas”, Petras”, “Ona”, “Antanas”}; // string objektų masyvas

set > nameSet(names, names+4); // aibė į masyvą

set >::iterator iter; // iteratorius

nameSet.insert(“Jurgis”);

nameSet.insert(“Mikas”);

cout<<“Size”<
#include
#include

void main()
{ string names [ ] = {“Jonas”, Petras”, “Ona”, “Antanas”};

// string objektų masyvas

set > nameSet(names, names+4);

// aibė į masyvą

set >::iterator iter;
// iteratorius

nameSet.insert(“Jurgis”);
// įterpiamas naujas vardas

nameSet.insert(“Mikas”);

nameSet.erase(“Mikas”);

// šalinamas elementas

cout<<“Size”<> searchName;
iter = nameSet.find(searchName);
if ( iter == nameSet.end() )

cout << “ Vardas “<< searchName << “nerastas” << endl;
else

cout << “Vardas “<<*iter << “rastas.”<
#include
#include

void main()
{ string name; int pop;

string states[ ] = {“Montana”, “Arizona”, “Nevada”, “Colorado”, “Florida”};

int pops[ ] = {470, 280, 787, 985, 562};

map > mapStates; //map

map > :: iterator iter; //iterator

// string – eilute(raktas), int – reikšmė, less – išrūšiavimas mažėjimo tvarka

for (int j = 0; j<6; j++)
{ name = states[ j ];

pop = pops[ j ];

mapstates [name] = pop;
}

cout << “Įveskite valstiją: “; cin >> name;

cout << “Gyventojų skaičius “<y
bool = less(T, T) x=y
bool = less_equal(T, T) x<=y
Pavyzdys
#include
#include
#include
// del funkcijos accumulate()
class airtime
{private: int hours;

int minutes;

public: airtime(): hours (0), minutes (0)

{ }

airtime (int h, int min): hours (h), minutes (min)

{ }

void display ( ) const

{ cout << hours << “ : “ <> hours >> dummy>>minutes; }
airtime operator + (const airtime right) const
// perktrautas operatorius
{ int tmph = hours + right.hours;

int tmpmin = minutes + right.minutes

if (tmpmin >= 60)

{tmph ++; tmpmin -= 60; }

return airtime(tmph, tmpmin); }
bool operator = = (const airtime& at2) const
{return (hours = = at2.hours)&&(minutes = = at2.minutes) }
};
void main ()
{char answer;

airtime temp, sum;

list airlist;

// sąrašas padarytas iš airtime

do {

temp.get ();

airlist.push_back (temp);

// įterpiamas objektas temp sąrašo gale

cout >> “ Dar įvedinėsite (y/n)? ” ;

cin >> answer;

} while (answer != ‘n’);

sum = accumulate (airlist.begin(), airlist.end(), airtime(0,0), plus() );
sum.display();
cout << endl; }

Funkcija accumulate() sudeda sąrašo elementus pradedant nuo pirmo ir baigiant paskutiniuoju. Sudėčiai naudojama funkcija objektas plus, sumavimas atliekamas į airtime(0,0) objektą.

Objektiškai orientuotas projektavimas
OOD (object oriented design) – tai programuojamos problemos modelio sukūrimas, naudojant klases bei jų savybes.
OOD sudaro trys fazes:

1. CRC card (CRC kortelė)

2. Use cases (Panaudojimo stadija)

3. Class diagrams (Klasių diagramos)
CRC cards – tai problemos analizė netechniniu požiūriu. Tai paprastai atlieka business domain experts (BDEs), kurie žino kaip programa turi veikti. Kiekviena kortelė atitinka tam tikrą objektą, kuris bus naudojamas programoje.
Use case – tai programos specifinių operacijų aprašymas. Šitoje stadijoje gali išaiskėti, kad CRC cards turi būti modifikuotos ar sukurtos naujos papildomos.
Class diagrams – tai stadija, kai nustatomas ryšys tarp planuojamų sukurti klasių bei įrašoma informacija į CRC cards. Šioje stadijoje naudojama UML (Universal Modeling Language).

Leave a Comment