Informatyka - C++

1. C to proceduralny język imperatywny:

  • język proceduralny (język programowania pozwalający na wydzielenie podprogramów realizujących pewne zadania)
  • język imperatywny (opisuje proces wykonywania jako sekwencję instrukcji zmieniających stan programu)
2. C++ jest ewolucją języka C. Został rozszerzony o obiektowość. W szerokim zarysie jest kompatybilny z językiem C. Wprowadził pojęcia klasy, obiektu, dziedziczenia do języka C.

3. Narzędzia potrzebne do programowania w C/C++ to kompilator, linker, preprocesor. 

4. Programem służącym do projektowania aplikacji w języku C i C++ jest m.in. CodeBlocks.

5. Kompilator to program służący do tłumaczenia języka na język maszynowy. 

6. Dyrektywa #include pozwala na dołączanie plików do własnego programu. Domyślnie jest to <iostream>, ale są także m.in. <cmath><cstdio>

7. Standardową przestrzenią nazw w języku C++ jest przestrzeń std. Za pomocą słów kluczowych using namespace informujemy kompilator, że wszystkie klasy, funkcje i szablony powinny należeć do danej przestrzeni nazw (np. using namespace std;).

8. Podstawy języka C++:

Do wyświetlania tekstu w oknie konsoli służy obiekt cout

#include <iostream>
using namespace std;

int main() { // rozpoczęcie nowej funkcji języka C++
  cout << "Witaj!";
  return 0; // to kończy główną funkcję jaką jest funkcja "main"
}

Aby przejść do nowej linii używa się \n lub endl:

cout << "Ucze sie C++" \n";
cout << "Hello World!" << endl;

Aby kompilator mógł wyświetlić polskie znaki w konsoli należy użyć:

Komentarze są ignorowane w trakcie przetwarzania kodu. Stosuje się je głównie do opisywania co dany blok kodu robi (dla ułatwienia przy ewentualnej późniejszej edycji kodu). W języku C++ komentarz aby rozpocząć komentarz "jednoliniowy" stosuje się // , a jeśli chcemy rozpocząć komentarz "wieloliniowy" wówczas stosuje się /* jakiś komentarz */.

Zmienna służy do przechowywania danych i wyników wykonywanych operacji. W języku C++ mamy następujące typy zmiennych:
  • int (liczby całkowite)
  • double (liczby, które posiadają 2 miejsca po przecinku)
  • char (dowolny pojedynczy znak)
  • string (przechowuje tekst)
  • bool (przechowuje wartości: prawda - 1 lub fałsz - 0)
W języku C++ należy zdefiniować typ zmiennej np. int a (zmienna o nazwie a typu int). W jednej linii można definiować wiele zmiennych, które są tego samego typu np. int x,y,z.

Stała to symbol, któremu przypisana wartość nie może zostać zmieniona np.
const int a;

Strumień wejściowy cin pozwala na wczytywanie danych wpisanych z klawiatury. np. 
int a;
cin >> a;
cout >> "Zmienna ma wartosc " >>  a; 





Aby obliczyć długość stringa używa się funkcji length() lub size().

np.
  string txt = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  cout << "Długosc tekstu wynosi: " << txt.length();

  string txt = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  cout << "Długosc tekstu wynosi: " << txt.size();

  • min() / max()  - szuka w zbiorze tą liczbę, która jest największa
Funkcje matematyczne wymagające zainicjowania biblioteki <cmath>:
  • sin(x) - oblicza sinus danej liczby
  • cos(x) - oblicza cosinus danej liczby
  • tan(x) - oblicza tangens danej liczby
  • pow(x,y) - oblicza x do potęgi y
  • sqrt(x) - oblicza pierwiastek kwadratowy z danej liczby
  • ceil(x) - zaokrągla liczbę x do pełnej liczby
  • hypot(x,y) - oblicza długość przeciwprostokątnej trójkąta prostokątnego, gdzie x i y to długości przyprostokątnych
Instrukcje warunkowe pozwalają na wykonywanie różnych instrukcji w zależności od tego czy zdefiniowane wyrażenie logiczne jest prawdziwe, czy fałszywe.

int time = 20;
if (time < 18) {
  cout << "Good day.";
} else {
  cout << "Good evening.";
}


int time = 20;
string result = (time < 18) ? "Good day." : "Good evening.";
cout << result;

Switch sprawdza, czy pewna wartość jest równa innym. Używa się w nim zwykle break lub continue.

  int owoc = 3;
  switch (owoc) {
  case 1:
    cout << "Zjesz jabłko";
    break;
  case 2:
    cout << "Zjesz gruszke";
    break;
  case 3:
    cout << "Zjesz brzoskwinie";
    break;
    default: // gdy wartość zmiennej owoc nie będzie odpowiadała 1 lub 2 lub 3 to wyświetliłoby się to:
    cout << "Nic nie zjesz....";
  }

Pętla umożliwia cykliczne wykonywanie ciągu instrukcji przez określoną liczbę razy, do momentu zajścia pewnych warunków. W języku C++ posiadamy pętle:
  • while
  • do-while
  • for
Składnia pętli while:

int i = 0; // ustawiamy, że i ma być równe 0
while (i < 5) { // pętla będzie się wykonywała dopóki i będzie mniejsze od 5
  cout << i << "\n";
  i++; //inkrementacja
}

To samo tylko w pętli do-while:

int i = 0;
do {
  cout << i << "\n";
  i++;
}
while (i < 5);

To samo w pętli for:

for (int i = 0; i < 5; i++) {
  cout << i << "\n";
}

Instrukcja break przerywa wykonywanie najbliższej otaczającej pętli lub instrukcji warunkowej, w której występuje. Jeśli po końcu przerwanej instrukcji występuje kolejna, sterowanie przechodzi do niej.

np. 
for (int i = 0; i < 10; i++) {
  if (i == 4) {
    break; 
  }
  cout << i << "\n"; // wyświetli się 0,1,2,3 (4 i dalej nie wyświetli ponieważ, gdy i będzie równe 4 to blok kodu ma zostać przerwany 
}

Instrukcja continue przerywa dane przejście pętli (gdy spełniony jest dany warunek), a następnie wykonuje kolejne przejście pętli.

np.
for (int i = 0; i < 10; i++) {
  if (i == 4) {
    continue;
  }
  cout << i << "\n"; // wyświetli się 0,1,2,3,5,6,7,8,9, bo przy 4 przejście zostaje przerwane
}

Tablice służą do zapisywania kilku wartości pod jedną zmienną. Każda wartość ma swój indeks, do którego możemy się odwołać np. w przypadku, kiedy chcemy wyświetlić to co się znajduje w tablicy. Tablice tworzy się poprzez string nazwa_tablicy[liczba ile elementów ma być w tablicy].

np. 
string samochody[4]; // tworzymy bez przypisania wartości
string samochody[4] = {"Volvo", "BMW", "Ford", "Mazda"}; // z przypisaniem wartości pod każdy klucz

Indeksy w tablicach liczy się od zera. Zatem: Volvo ma indeks 0, BMW indeks 1, Ford - 2 itd.

Jeśli chcemy przypisać/zmienić wartość w tablicy to wówczas przypisujemy wartość w następujący sposób:
np. samochody[0] = "Bugatti";

Wyświetlanie danych z tablicy:

for(int i = 0; i < 4; i++) {
  cout << samochody[i] << "\n";
}

W tablicach możemy przechowywać dane, które są tego samego typu (w powyższym przykładzie są to stringi). Jeśli chcemy pracować na różnych typach obiektów możemy stworzyć tzw. strukturę.

np.
struct samochod{
string marka; // pierwszym elementem struktury jest marka (string)
string model; // drugim model (string)
int rok_produkcji; // trzecim rok produkcji (int)
double pojemnosc; // czwartym pojemność (double)
};

Nadawanie wartości do struktury:

np.
samochod SUV{"Hyundai","Santa Fe",2009,2.0;}; // w nawiasach klamrowych podajemy kolejno dane do poszczególnych elementów struktury 

Odwoływanie się do elementów składowych następuje poprzez podanie nazwy zmiennej strukturalnej (w naszym przypadku "SUV"), a po kropce nazwę składowej struktury (np. marka, model, rok_produkcji, pojemnosc).

np.
cout << "Pojemność tego samochodu wynosi: "  << SUV.pojemnosc; 

Funkcja jest blokiem kodu, który ma się wykonać w momencie jego wywołania. Funkcja main() jest zawsze pierwszą funkcją uruchamianą (nawet wtedy kiedy zdefiniujemy inne funkcje przed main()) i zawsze zwraca jakąś wartość. Jeśli w kodzie na końcu tej funkcji mamy zapisane return 0 i po uruchomieniu programu, na końcu zostanie zwrócone 0 - wówczas mamy pewność, że kod został wykonany poprawnie. 
W języku C++ możemy stworzyć funkcję, która nie musi zwracać żadnej wartości. Tworzy się ją przy pomocy void. W nawiasie możemy przekazać parametry.

np.
void funkcja() {
  cout << "Funkcja została wykonana poprawnie. ";
}

int main() {
  funkcja(); // w main`ie musimy podać, że funkcja ma się wykonać!
  return 0;
}

Jeśli chcemy stworzyć funkcję, która zwraca jakąś wartość, wówczas możemy to zrobić to przy pomocy int. 

Na ciągach znaków (string) można wykonywać różne operacje.
Załóżmy, że tworzymy dwie zmienne typu string:

string s1,s2;
  • s1+s2 - łączenie dwóch ciągów znaków
  • s1.length() - zwraca liczbę znaków tekstu
  • s1[2] - zwraca trzeci znak ciągu (pozycje liter w stringach są numerowane tak jak dane w tablicach)
  • s1.substr(1,3) - zwraca znaki ciągu, które są od miejsca drugiego do czwartego włącznie (czyli np. w słowie bliźniak zwróci liź)
  • s1.erase(1,3) - usuwa znaki ciągu, które są od miejsca drugiego do czwartego włącznie (czyli np. w słowie bliźniak usunie liź)
  • s1.find("krokodyl") - zwraca numer pozycji, od której zaczyna się słowo krokodyl w danym ciągu znaków (jeśli zwróci liczbę ujemną, wówczas to oznacza, że nie ma danego słowa w stringu.
  • getline(cin,s1) - pobiera do zmiennej s1 cały tekst ze strumienia cin
  • s1.c_str() - zwraca tekst w formacie Null-terminated
  • s1.atof() - zamienia tekst do formy zmiennoprzecinkowej
  • s1.atoi() - zamienia tekst na liczbę całkowitą

Liczby losowe obsługiwane są przez bibliotekę cstdlib:
  • rand() - losuje liczbę całkowitą od 0 RAND_MAX (włącznie)
  • RAND_MAX - liczba całkowita zależna od kompilatora (wynosie min. 32767)
  • srand(x) - inicjuje generator liczb losowych zależnie od x
  • time(0) - zwraca aktualny czas w formacie DD-MM-RRRR HH:MM (biblioteka ctime)
np. - generowanie liczby całkowitej losowej od 0 do liczby, którą poda użytkownik:

int i,j;  // tworzymy dwie zmienne typu int
cin >> i; // wprowadzamy do jakiej liczby włącznie ma być wylosowana liczba
j = i*rand()/RAND_MAX;  // wykonujemy działanie
cout << j; // wyświetla wylosowaną liczbę

Wskaźnik umożliwia nam pobranie adresu pamięci wybranych zmiennych. Zajmuje on zawsze 4 bajty.

Jak pobrać adres dowolnej zmiennej?
np.
int i;
cout << &i; // poprzesz ampersand 

Aby stworzyć zmienną wskaźnikową (czyli tej zmiennej, która ma pokazywać adres pamięci innej zmiennej), to po typie zmiennej dopisujemy gwiazdkę (*) 
np.
int* j;

np.
string food = "Pizza";  // Tworzymy zmienną typu string i od razu definiujemy jej wartość
string* ptr = &food;  // Tworzymy zmienną wskaźnikową (która będzie przechowywała adres pamięci                                       // zmiennej food
cout << food << "\n"; // Wyświetlamy wartość zmiennej food
cout << &food << "\n"; // Wyświetlamy adres pamięci zmiennej food (bezpośrednio)
cout << ptr << "\n"; // Wyświetlamy adres pamięci zmiennej food (pośrednio; przez wskaźnik ptr)

UWAGA! Jeśli chcemy stworzyć dwie zmienne wskaźnikowe na raz, wówczas musimy zrobić:
int *w1, *w2 (NIE: int* w1,w2 !)

Operacje na plikach:

Biblioteka <fstream>  pozwala na operacje na plikach przy pomocy języka C++. 

Tworzenie pliku tekstowego:

ofstream plik1 // plik1 to obiekt klasy odnoszący się ogólnie do tego pliku
plik1.open("plik.txt"); // otwieramy plik 

Zapisywanie danych do pliku tekstowego:

plik1 >> "Ten tekst ma byc zapisany w pliku"; 
plik1.close(); // zamykamy plik

Odczytywanie danych z pliku tekstowego:

ifstream plik1; // tworzymy obiekt klasy ifstream
plik1.open(plik1.txt); // otwieramy plik, który mamy odczytać
string text; // tworzymy stringa
plik1 << text; // string zostaje wyświetlony
plik1.close() // zamykamy plik

9. Programowanie obiektowe polega na tworzeniu obiektów, które zawierają dane i funkcje. Programowanie to jest szybsze i łatwiejsze do wykonania w porównaniu do podejścia proceduralnego, kod programu jest przejrzystszy, nie trzeba go powtarzać.

10. Klasa to zestaw cech oraz możliwych akcji na podstawie, której został zbudowany obiekt. Obiekt jest reprezentantem klasy.

Specyfikatory dostępu:
  • public - dostęp publiczny do wszystkich składowych klasy
  • private - metody tej klasy mają dostęp do składowych klasy (domyślne)
  • protected - składowa klasy lub metoda będą dostępne w klasach pochodnych danej klasy, ale zachowują się tak jakby były prywatne dla wszystkich innych klas i funkcji
Członkowie klasy bez specyfikatora dostępu domyślnie są prywatni. Członkowie struktur i stowrzyszeń są domyślnie publiczni.

11. Obiekt to wycinek rzeczywistości posiadający własne cechy (właściwości) oraz mogący wykonywać pewne funkcje (metody).

12. Metoda to funkcja w klasie. Klasyfikacja metod:
  • w odniesieniu do klasy: wewnętrzne metody, zewnętrzne metody, przyjazne
  • z załącznikiem do obiektu lub klasy: statyczna, dynamiczna
  • z możliwością pracy ze stałymi obiektami: stała, niestała
np.
class Samochod{
    public: // właściwości klasy:
        string marka, model;
        int rocznik;

        void dodaj_samochod(){ // metoda
            cin >> marka;
            cin >> model;
            cin >> rocznik;
        }

}

int main(){
s1.dodaj_samochod(); // obiekt

return 0;
}

13. Właściwości programowania obiektowego:
  • abstrakcja - wyodrębnienie z rzeczywistości oraz uproszczenie najważniejszych cech problemu i wyrażenie rozwiązania w obrębie cech
  • hermetyzacja - ukrywanie pewnych danych składowych lub metod obiektów danej klasy tak, aby były one dostępne tylko metodom składowym danej klasy lub funkcjom zaprzyjaźnionym
  • polimorfizm - używanie jednej nazwy dla różnych jednostek
  • dziedziczenie - powtórne wykorzystanie cech oraz działań klasy podstawowej przez klasę pochodną oraz rozszerzenie klasy podstawowej o nowe metody
14. Konstruktor - specjalna metoda składowa klasy wywoływana podczas tworzenia obiektu tej klasy. Zadaniem konstruktora jest zainicjowanie obiektu, czyli przypisanie atrybutom wartości startowych. Konstruktor ma taką samą nazwę jak klasa i jest wywoływany automatycznie tyle ile razy powołujemy do życia nowy obiekt danej klasy.

np. 
class Klasa{
    string haslo;
    public:
        Klasa(){
            cout << "Wprowadz haslo";
            cin >> haslo;
}
};

int main(){
    Klasa has1;
    return 0;
}

W językach C każda funkcja musi mieć swoją unikatową nazwę. W języku C++ możliwe jest jednak zdefiniowanie kilku funkcji o takich samych nazwach, ale z unikalnymi typami argumentów (przeciążenie funkcji).

np.
void funkcja (string);
int funkcja (double);
int funkcja (bool);

Przeciążone funkcje powinny różnić się liczbą argumentów oraz typem lub kolejnością co najmniej dwóch argumentów. Nie różnią się natomiast typem jakim ta funkcja zwraca, specyfikatorem przed typem zmiennej oraz referencją przed zmienną. 

Operator rozpoznawania zakresu :: umożliwia dostęp do zmiennej globalnej lub funkcji z bloku, w którym zdeklarowana jest zmienna lokalna o tej samej nazwie.

np.
   int i; // zmienna globalna

int main(){
    int i;
    x = 0; // wartość w zmiennej lokalnej
    ::x = 1; // wartość w zmiennej globalnej
}

15. Destruktor - specjalna metoda, wywoływana tuż przed usunięciem obiektu, mająca za zadanie wykonać czynności składające się na jego "zniszczenie", inne niż zwolnienie pamięci zajmowanej przez sam obiekt. Destruktor ma nazwę taką jak klasa poprzedzoną znakiem ~ (tyldy). Destruktor jest automatycznie wywoływany kiedy obiekt klasy jest likwidowany.

16. Przestrzeń nazw to sposób grupowania logicznego. Operator ten może być również używany do odwoływania się do funkcji z namespace spoza przestrzeni.

np.
namespace przestrzen{
    int i; 
}

int main(){
    int i;
    x = 0; // wartość w zmiennej lokalnej
    ::x = 1; // odwołanie się do funkcji z innej przestrzeni
}

Funkcja inline - kompilator widząc że funkcja jest inline w miejsce jej wywołania nie wstawia jak w normalnym przypadku wskaźnika do tej funkcji w pamięci, lecz wpisuje jej kod w miejsce jej wystąpienia. 

np.
void display(int a){ 
    cout << a <<endl;
}

int main(){
    display(10);
    return 0;
}

Nie używa się tego przy dużych funkcjach!!!

this - to wskaźnik wskazujący na obiekt, dla którego została wywołana metoda.

np.
class X{
    public:
    void Y(){
            cout << this << endl;
       }
};

17. Polimorfizm to cecha programowania obiektowego, która umożliwia różne zachowanie tych samych metod wirtualnych w czasie wykonywania programu. Metoda wirtualna jest funkcją składową danej klasy (virtual)