komponenty klasy (zmienne i metody) zadeklarowane bez Access Specifier (private public)
będą zawsze private
Przykładowe zaimplementowanie stosu bez klasy:
#include <iostream> using namespace std; int stack[100]; int SP = 0; void push(int value) { stack[SP++] = value; } int pop(void) { return stack[--SP]; } int main(void) { push(3); push(2); push(1); cout << pop() << endl; cout << pop() << endl; cout << pop() << endl; return 0; }
.
przykład z zastosowaniem klasy:
class Stack { private: int stackstore[100]; int SP; public: Stack(void) { SP = 0; } void push(int value); int pop(void) { return stackstore[--SP]; } }; void Stack::push(int value) { stackstore[SP++] = value; }
.
DZIEDZICZENIE
class Nowa:Stara{ };
możemy dodać nowe zmienne
możemy nadpisać stare metody (funkcje)
przykład:
class AddingStack : Stack {
private:
int sum;
public:
void push(int value);
int pop(void);
};
i nadpisana metoda:
void AddingStack::push(int value) {
sum += value;
Stack::push(value); // jak widać wywołujemy starą metodę push
}
UWAGA żeby stworzyć konstruktor do klasy pochodnej, trzeba wspomnieć konstruktor
superklasy (tu Stack), będzie on wywołany przed konstruktorem klasy pochodnej
AddingStack::AddingStack(void) : Stack() { //zapis z :: gdy ciało poza klasą, w ciele prototyp;
sum = 0;
}
metody klas mają pełen dostęp do zmiennych różnież prywatnych, za ich pomocą powinno się ustawiać wartość prywatnych zmiennych
przykład:
class Class {
public:
void setVal(int value) {
Class::value = value;
}
private:
int value;
};
zastąpienie notacji Nazwa::Metoda this ->
class Class {
public:
void setVal(int value) {
this -> value = value;
}
private:
int value;
};
Jeśli chcemy przeciążyć Metodę setVal
void setVal(int value) {
this -> value = value;
}
void setVal(void) {
value = -2;
}
UWAGA Konstruktor nigdy nie zwraca nawet nie trzeba pisać VOID i nie może mieć returna
przykład:
class Class {
public:
Class(void) { //konstruktor
this -> value = -1;
}
void setVal(int value) { this -> value = value; }
private:
int value;
};
Stworzenie obiektu
Class objekt1; // wywołuje powstanie konstruktora.
Konstruktor może być przeciążony.
przykład:
class Class {
public:
Class(void) { this -> value = -1; }
Class(int val) { this -> value = val; }
Jeśli masz TYLKO konstruktor z parametrem (nie void w nawiasie) nie możesz stworzyć
klasy Class objekt; tylko musisz Class objekt(1);
Konstruktor kopiujący
class Class {
public:
Class(int val) { this -> value = val; }
Class(Class const &source) { //konstruktor kopiujący
value = source.value + 100; //uruchamiany przy kop. obiektow
} //np objekt2=objekt1;
int value;
};
Destruktor
przykład:
class Class {
public:
Class(int val) {
value = new int[val]; /tablica o wielkosci val
}
~Class(void) {
delete [] value;
}
int *value;
};
AUTO - każda zmienna jest auto w c++, ale możemy ją zamienić na STATIC
istnieje wtedy przez cały czas, jeśli jest w funkcji to pozostaje po czasie istnienia funkcji
Statyczne komponenty Klasy:
można dać zmienną statyczną w klasie, będzie ona istniała nawet bez obiektu, ale co ważne
w klasie można ją jedynie zadeklarować, jej pierwsza inicjacja musi być poza klasą i PRZED MAIN
(w obszarze zmiennych GLOBALNYCH)
class Class {
public:
static int Static;
};
int Class::Static = 0; // inicjacja statycznej zmiennej poza klasą w obszarze GLOBALNYM
int main(void) {
Class instance1; // stworzenie obiektu który już ma tą wartość
zmienna statyczna może oczywiście być prywatna.
Statyczne również mogą być metody (funkcje) w klasie.
przykład
...
static void HowMany(void) {
cout << Counter << " instances" << endl;
}
...
wtedy możemy taką metodę wywoływać:
HowMany(); // w srodku klasy
a.HowMany(); //dla istniejącego obiektu
Class:HowMany(); //wywołanie bez obiektu za pomoca klasy
Metoda statyczna nie może wywoływać zwykłej, bo ta może jeszcze nie istnieć, może statyczna.
Wskaźnik do obiektów i tworzenie za pomocą NEW
Clasa *ptr; //wskaźnik o typie klasy
ptr=new Clasa();
kasowanie:
delete ptr;
jeśli chcemy wywołać metodę albo odwołać się do zmiennej w obiekcie do któego mamy dostęp
przez wskaźnik to:
(*ptr).value=0;
albo
ptr->value=0
do metody (funkcji też można się tak odwołac )
ptr->funkcja();
zmienne, obiekty tworzone w zwykły sposób odkładane są na stosie, tworzone za pomocą NEW na stercie (heap), nad stertą mamy pełną kontrolę
Konstruktory w obszarze public (i mogą być przeciążane )
Przykład tablicy tablic stworzonych NEW:
#include <iostream> using namespace std; class Array { int *values; int size; public: Array(int siz) { size = siz; values = new int[size]; cout << "Array of " << size << " ints constructed." << endl; } ~Array(void) { delete [] values; cout << "Array of " << size << " ints destructed." << endl; } int Get(int ix) { return values[ix]; } void Put(int ix, int val) { values[ix] = val; } }; int main(void) { Array *arr[2] = { new Array(2), new Array(2) }; for(int i = 0; i < 2; i++) for(int j = 0; j < 2; j++) arr[i]->Put(j, j + 10 + i); for(int i = 0; i < 2; i++) { for(int j = 0; j < 2; j++) cout << "#" << i + 1 << ":" << arr[i]->Get(j) << "; "; cout << endl; } delete arr[0]; delete arr[1]; return 0; }
Jeśli mamy 2 klasy i druga w swoim polu tworzy obiekty pierwszej, to nie ma problemu jeśli pierwsza nie potrzebuje parametrów:
class Element {
int value;
public:
Element(void) { cout<<"stworzylem";} // konstruktor pierwszego (void)
};
class Collection {
Element el1, el2; //w 2 klasie tworzymy obiekty 1 klasy
public:
Collection(void) { cout << "Collection constructed!" << endl; } //konstruktor 2 klasy
Ale jeśli 1 klasa potrzebuje parametrów (konstruktor nie z void)
class Element {
int value;
public:
Element(int val) { value=val;} // konstruktor pierwszego (void)
};
to konstruktor 2 klasy musi wyglądać TAK:
class Collection {
Element el1, el2;
public:
Collection(void) : el2(2), el1(1) { cout << "Collection constructed!" << endl; }
w konstruktorze nie można przypisać zmiennej cons żadnej wartości, ponieważ podczas wywołania konstruktora obiekt już istnieje. Poniższy przykład nie skompiluje się:
class Osoba {
public:
const int wiek;
const int wzrost;
string imie;
Osoba(int WIEK, int WZROST, string IMIE) {
// błąd kompilacji !!!
this->wiek = WIEK;
this->wzrost = WZROST;
this->imie = IMIE;
}
};
|
Obowiązek użycia listy inicjalizacyjnej :
1)Przypisanie wartości do zmiennej CONST
2)Utworzenie w obiekcie innego obiektu KTÓRY POTRZEBUJE ARGUMENTÓW
Zamierzony efekt można osiągnąć używając listy inicjalizacyjnej. Składowe wiek oraz wzrost musimy zainicjalizować na liście, jednak wartość składowej imie można przypisać w konstruktorze:
1)Przypisanie wartości do zmiennej CONST
2)Utworzenie w obiekcie innego obiektu KTÓRY POTRZEBUJE ARGUMENTÓW
Zamierzony efekt można osiągnąć używając listy inicjalizacyjnej. Składowe wiek oraz wzrost musimy zainicjalizować na liście, jednak wartość składowej imie można przypisać w konstruktorze:
class Osoba {
public:
const int wiek;
const int wzrost;
string imie;
Osoba(int WIEK, int WZROST, string IMIE) : wiek(WIEK), wzrost(WZROST) {
this->imie = IMIE;
}
};
|
Jeżeli jest taka możliwość, powinno się jednak wszystkie możliwe składowe inicjalizować za pomocą listy inicjalizacyjnej, ponieważ jest to rozwiązanie szybsze i wydajniejsze od użycia konstruktorów.
ZADANIA:
Zad1:
#include <iostream>
#include <string>
using namespace std;
class A {
public: string a(string b) { //funkcja a zwracajaca strinf a przyjmujaca string b
return b.substr(0,2);
}};
class B {
public: string a(string b) {
return b.substr(2,2);
}};
int main() {
A a;
B b;
cout << a.a(b.a("ABCD")); // najpierw 2 wycina CD a potem pierwsza 0 do 2
return 0; // czyli zostaje CD
}
Wynik CD
Zad2:
#include <iostream>
using namespace std;
class A {
public:
float v;
float set(float v) {
v += 1.0; //tutaj v odnosi sie do argumentu bo argument v
this -> v = v; //a do v klasy(obiektu) musimy odnosic sie przez this
return v;
}
float get(float d) { //tutaj v odnosi się do v klasy i obiektu, bo argument inny niz v
v += 1.0;
return v;
}
};
int main() {
A a;
cout << a.get(a.set(a.set(0.5)));
return 0;
}
Wynik 3.5
#include <iostream>
using namespace std;
class A {
public:
A() { v = 2.5; } //konstruktor
float v;
float set(float v) {
A::v += 1.0;
return v;
}
float get(float v) {
v += A::v;
return v;
}
};
int main() {
A a;
cout << a.get(a.set(1.5));
return 0;
}
Wynik 5
Zad4:
#include <iostream>
using namespace std;
class A {
public:
float v;
A() : v(1.0) {} //lista inicjalizacyjna
A(A &a) : v(2.0) {}
A(float f) : v(3.0) {}
float get() {
return A::v;
}
};
int main() {
A a, b(a.get()), c(b);
cout << a.v + b.v + c.v;
return 0;
}