Struktura programu w języku C++:
Dyrektywy procesora poprzedzone znakiem #, najczęściej wykorzystywana jest dyrektywa include służy do wczytywania plików nagłówkowych,
#include<iostream.h>
wykorzystywane przestrzenie nazw wszystkie elementy zdefiniowane w języku C++ są zdefiniowane w przestrzeni nazw, konkretnie w przestrzeni o nazwie std.
using namespace nazwa;
gdzie nazwa jest nazwą wybranej przestrzeni nazw.
Funkcje zdefiniowane przez użytkownika,
Główna funkcja programu main
INSTRUKCJE WARUNKOWE
if
if ( warunek ) instrukcja_1;
Np.
if (i_zmienna == 0){
cout << "wartosc zmiennej wynosi 0";
}
if (warunek_1) instrukcja_1;
else if (warunek_2) instrukcja_2;
else if(warunek_3) instrukcja_3;
else if(warunek_N) instrukcja_N;
Np.
{
cout << "zmienna jest wieksza od 0";
}
else
{
cout << "zmienna jest mniejsza lub rowna 0";
}
while (wyrażenie) instrukcja;
najpierw obliczana jest wartość wyrażenia w nawiasie, jeżeli jego wartość jest prawdziwa (niezerowa), to następuje wykonywanie instrukcji tak długo, aż wyrażenie w nawiasie przyjmie wartość zerową (fałsz). Wyrażenie obliczane jest przed wykonaniem instrukcji.
main()
{
int a,b;
cout<<”Podaj a:”; cin>>a;
b=0;
while (a<10)
{
a=a+1;
b=b+1;
}
cout<<”a=”<<a<<endl;
cout<<”Liczba powtorzen=”; cout<<b;
getch();
}
do instrukcja while (wyrażenie);
najpierw wykonywana jest instrukcja, a później wartość wyrażenia w nawiasie, instrukcja wykonuje się tak długo, póki wyrażenie jest prawdziwe (wartość niezerowa). Gdy wyrażenie przyjmie wartość fałszywą, instrukcja zatrzymuje się. Instrukcja wykonywana jest co najmniej raz.
#include <iostream.h>
#include <conio.h>
main()
{
int a,b;
cout<<”Podaj a:”; cin>>a;
b=0;
do {
a=a+1;
b=b+1;
}
while (a<10);
cout<<”a=”<<a<<endl;
cout<<”Liczba powtorzen=”; cout<<b;
getch();
}
for (ini; wyraz_warunkowe; krok) treść_pętli;
ini – instrukcja inicjująca wykonywanie pętli for;
wyraz_warunkowe – wyrażenie obliczane przed każdym obiegiem pętli. Gdy jest różne od zera, to wykonywane zostaną instrukcje będące treścią pętli,
krok – instrukcja wykonywana na zakończenie każdego obiegu pętli. Jest to ostatnia instrukcja wykonywana bezpośrednio przed obliczeniem wartości wyraz_warunkowe.
#include <iostream.h>
#include <conio.h>
main()
{
int i,j;
for(i=1, j=1; i<55; i=i+1, j=j+2)
cout<<”i=” <<i<<”j=” <<j<< endl;
getch();
}
switch (wyrażenie)
{
case wart_1: {instr_1;
break;}
case wart_2: {instr_2;
break;}
…..
case wart_n: {instr_n;
break;}
default : instr_(n+1);
break;}
}
Instrukcja switch przyjmuje jako parametr jakąś zmienną i wg tej wartości obsługuje poszczególne przypadki, które definiujemy następującymi po sobie instrukcjami case,
Obok każdej instrukcji case występuje wartość, w przypadku wystąpienia tej wartości, wykonywane jest wszystko, co znajduje się między instrukcją case, a odpowiadającą jej instukcją break;.
Wewnątrz instrukcji switch (nawiasy klamrowe), może wystąpić dowolna ilość obsługi warunków w postaci case-break;.
default-break; załatwia nam obsługę wszystkich sytuacji które nie zostały wymienione.
/*-----przykład instrukcji switch ----------------------------------------*/
/* Program oblicza stopień na podstawie liczby otrzymanych */
/* punktów. Kryteria: */
/* 0.. 49 pkt. - 2 */
/* 50.. 59 pkt. - 3 */
/* 60.. 69 pkt. - 3.5 */
/* 70.. 79 pkt. - 4 */
/* 80.. 89 pkt. - 4.5 */
/* 90..100 pkt. - 5 */
/*--------------------------------------------------------------------------------*/
#include <iostream.h>
#include <conio.h>
main ()
{
int lp;
float stopien;
clrscr ();
cout << "Podaj liczbę punktów (0 <= lp <= 100): "; cin >> lp;
lp = lp/10; //dzielenie bez reszty
switch (lp)
{
case 5 : { stopien = 3; break;}
case 6 : { stopien = 3.5; break;}
case 7 : { stopien = 4; break;}
case 8 : { stopien = 4.5; break;}
case 9,10 : { stopien = 5; break;}
default : { stopien = 2; break;}
}
cout << "Twoja ocena: ";
cout.width(3); cout.precision(1); //format wydruku
cout << stopien << endl;
getch();
}
TYPEDEF – instrukcja typedef pozwala na nadanie dodatkowej nazwy już istniejącemu typowi np.:
typedef int cena;
cena x; //co odpowiada int x;
cena a, b, c // co odpowiada int a,b,c;
wiosek: instrukcja typedef nie wprowadza nowego typu. Umożliwia tworzenie jedynie synonimu do typu już istniejącego.
ENUM
wyliczenie deklaruje się słowem kluczowym enum, po którym podaje się identyfikator oraz wykaz stałych oddzielonych przecinkiem i zamkniętych w nawiasy klamrowe.
Wymienionym stałym są przypisywane wartości domyślne: pierwszej z nich - wartość 0, a każdej następnej – wartość o 1 większą od poprzedzającej.
Wartości te można zmieniać np. nd=10
enum identyfikator {pn, wt, sr, czw, pt, sob, nd};
Wyszczególniony po enum identyfikator jest nazwą nowego typu np.:
#include <iostream.h>
#include <conio.h>
main()
{
enum dni_tyg {pn, wt, sr, czw, pt, sob, nd};
dni_tyg dzień; //dni_tyg nowy typ
dzien=pn;
dzien=wt;
dzien=sr;
getch();
}
Stałym typu wyliczeniowego można również przypisywać wartości jawne, przy czym wartości te mogą się powtarzać
enum identyfikator {pn=1, wt=2, sr=3, czw=4, pt=5, sob=6, nd=0};
enum logiczny {falsz=0, prawda=1};
OPERATORY:
arytmetyczne:
Operator | Działanie | Przykład |
---|---|---|
+ | dodawanie | a=b+c; |
- | odejmowanie | a=b-c; |
* | mnożenie | a=b*c; |
/ | dzielenie | a=b/c; |
% | reszta z dzielenia (modulo) | a=b%c; |
relacji:
Operator | działanie | Przykład |
---|---|---|
< | mniejszy | a<b |
<= | mniejszy lub równy | a<=b |
> | większy | a>b |
>= | większy lub równy | a>=b |
== | równy | a==b |
!= | nierówny | a!=b |
wszystkie operatory relacji są dwuargumentowe;
jeśli relacja jest prawdziwa, to jej wartością jest 1,
w przeciwnym przypadki wartością relacji jest 0.
logiczne:
Operator | działanie | Przykład |
---|---|---|
! | negacja | !a |
&& | koniunkcja (iloczyn logiczny) | a&&b |
|| | alternatywa (suma logiczna) | a||b |
wyrażenia połączone operatorami && i || zawsze są wartościowane od strony lewej do prawej,
kompilator oblicza wartość wyrażenia dotąd, dopóki na pewno nie wie, jaki będzie wynik.
bitowe:
Operator | działanie | Przykład |
---|---|---|
& | bitowa koniunkcja | a=b&c; |
| | bitowa alternatywa | a=b|c |
^ | bitowa różnica symetryczna | a=b^c |
<< | przesuniecie w lewo | a=b<<c |
>> | przesunięcie w prawo | a=b>>c |
~ | bitowa negacja | a=~b |
SPOSOBY PRZESYŁANIA ARGIMENTÓW DO FUNKCJI
przez wartość:
Przy wywołaniu funkcji posługujemy się parametrami aktualnymi.
Do funkcji macierzystej dodawana jest zmienna, następnie funkcja wykonuje się na tej zmiennej.
po jej wykonaniu zmienna zostaje usunięta, funkcja wraca do postaci pierwotnej
przez referencję:
Przy przekazywaniu argumentów do funkcji przez referencje trzeba inaczej zadeklarować funkcję np.:
void Zamiana (int, int &);
lub
void Zamiana (int x, int &y);
wywołanie:
zamiana (a,b);
Znak & powoduje, że zmienna globalna b i lokalna y zajmują to samo miejsce w pamięci operacyjnej. Inaczej – słowo b w pamięci ma referencje (przezwisko) y w funkcji. Modyfikując y w funkcji lokalnej, zmieniamy b w funkcji nadrzędnej.
Ten sposób przekazywania argumentów jest stosowany przy przekazywaniu do funkcji dużych struktur danych np.: tablic. Oszczędza się wówczas pamięć – nie tworzy się kopii dużych struktur danych na stosie. Trzeba uważać ze stosowaniem referencji, bo
#include <iostream>
using namespace std;
void Zamiana1(int a, int b) // przez wartość
{
int x;
x = a; a = b; b = x;
}
void Zamiana2(int &a, int &b) // przez referencję
{
int x;
x = a; a = b; b = x;
}
main()
{
int x = 12;
int y = 35;
cout << " x : y\n"
"-------\n"
<< x << " : " << y << endl;
Zamiana1(x,y);
cout << x << " : " << y << endl;
Zamiana2(x,y);
cout << x << " : " << y << endl << endl;
system("pause");
}
przez wskaźnik:
wskaźnik służy do wskazywania jakiegoś meijsca w pamięci (adresu) oraz zaiwra wiedzę o tym, jaki typ obiektu wskazuje, może przechowywać obiekty dowolnego typu,
FUNKCJA, JAKO ARGUMENT FUNKCJI
Jeśli program jest duży i nie mieści się w jednym pliku, to plik dzieli się na pliki mniejsze.
Plik można dzielić na mniejsze w miejscu między definicjami funkcji.
By korzystać w pliku B ze zmiennych zadeklarowanych w pliku A, to trzeba w pliku B umieścić deklarację:
extern int a;
extern float b;
extern char c;
Jeśli chcemy korzystać w pliku B z funkcji znajdujących się w pliku A, to także musimy umieścić je w deklaracjach pliku B (nie trzeba dodawać słowa extern – jest ono domniemane).
Wygodnie jest umieścić wszystkie deklaracje funkcji (i deklaracje globalne) w specjalnym pliku – pliku nagłówkowym (nazwa.h). Plik ten jest bezpośrednio przed kompilacją włączany do pliku B.
To automatyczne wstawianie realizuje dyrektywa preprocesora: #include <nazwa.h>
dyrektywa include służy do wstawiania do programu plików z eklaracjami zmiennych i funkcji
Funkcje biblioteczne nie są częścią języka C++. Ktoś je napisał, a ponieważ były dobre, to zrobiono z nich standardowe biblioteki.
TABLICE
Tablica to zbiór elementów tego samego typu, które zajmują ciągły obszar w pamięci. Tablice są typem pochodnym, tzn. buduje się je z elementów jakiegoś typu nazywanego typem składowym.
np.:
int A[5] to 5 elementów typu int, i tak: A[0], A[1], A[2], A[3], A[4]
numeracja elementów zaczyna się od zera,
element A[5] nie istnieje,
próba wpisania jakiejś wartości do A[5] nie będzie sygnalizowane jako błąd,
wpisanie wartości do nieistniejącego elementu A[5] spowoduje zniszczenie w obszarze pamięci wartości, wpisanej bezpośrednio za tablicą.
Inicjalizację tablicy można przeprowadzić w momencie definicji tablicy.
int A[5] = {20,21,22,23,24};
Wynik zainicjalizowania tablicy A:
A[0]=20
A[1]=21
A[2]=22
A[3]=23
A[4]=24
jeżeli w monecie inicjalizacji na liście jest więcej elementów, niż wynika z definicji, to kompilator zasygnalizuje błąd,
podczas inicjalizacji kombinator sprawdza, czy nie został przekroczony rozmiar tablicy.
OPERATOR &
Do nadania wskaźnikowi wartości początkowej służy jednoargumentowy operator & (ampersand). Oblicza on adres obiektu, który stoi po prawej stronie operatora przypisania.
Do czego slużą i jaką informację zawierają wskaźniki przykłady
Wskaźnik przechowuje adres obiektu wskazanego typu oraz wiedzę o typie danego obiektu. Wskaźnik służący do pokazywania obiektów jednego typu nie nadaje się zatem do pokazywania obiektów innego typu.
Podst. zastosowania wskaźników:
wskaźniki do tablic umożliwiające ulepszenie pracy tablicami;
w funkcjach do zmieniania wartości przesyłanych do nich (odbieranych) argumentów;
dostęp do specjalnych obszarów pamięci;
rezerwacja obszarów pamięci.
DEFINICJA STRUKTURY
struct nazwa
{
// lista składników
};
Dostęp do składowych struktury:
Nazwa_Zmienniej_strukturalnej . Nazwa_skladnika
DEFINICJA KLASY
Klasa jest zbiorem logicznie powiązanych danych i funkcji, przeznaczonych do realizacji konkretnego zadania.
Klasa abstrakcyjna, to klasa, która nie reprezentuje żadnego konkretnego obiektu.
Szablon funkcji Jest to mechanizm do tworzenia rodziny funkcji identycznych w działaniu, ale różniących się typem argumentów.
DOSTĘP DO KLAS
Są czy kategorie dostępu do elementu klas odpowiadają za to kwalifikatory dostępu:
private
public
protect
Kategorie dostępu określają sposób wykorzystania elementów klasy przez jej użytkownika.
DOSTEP DO STRUKTUR
flower.name;
flower.quantity;
flower.price
14. Konstruktor.
Jest specjalną funkcja składowa wywoływaną w chwili tworzenia obiektu danej klasy. Jego zadaniem jest inicjalizacja danych składowych obiektu danej klasy, przydzielanie pamięci dla jego elementów wykonanie innych czynności niezbędnych do prawidłowego utworzenia obiektu. Nie może zwracać żadnej wartości. Nazwa musi być taka sama jak nazwa zawierającej go klasy. Klasa może posiadać więcej niż jeden konstruktor, jest to możliwe dzięki mechanizmowi przeładowania.
Destruktor.
Jest specjalną funkcją wywołaną w chwili likwidacji obiektu danej klasy. Jest funkcjonalnym przeciwieństwem konstruktora. Zwalnia zasoby wykorzystane przez obiekt. Można zdefiniować tylko raz jest funkcją bezparametrową i nie zwraca żadnej wartości. Składa się z nazwy klasy poprzedzonej znakiem ~. Jest wywołany w chwili usuwania obiektu danej klasy.
15. czym różni się konstruktor i destruktor od funkcji składowych.
Definiowanie destruktora i konstruktora w obrębie szablonu klasy przebiega w identyczny sposób jak definicja zwykłej funkcji składowej. Również definiowanie konstruktora i destruktora poza ciałem szablonu klasy jest zbliżone do definicji zwykłej funkcji składowej - jedyna różnica polega na tym, że nie podajemy typu jaki zwraca dany konstruktor - destruktor!!!
16. THIS.
Deklaracja każdej klasy zawiera ukryte pole wskaźnikowe o nazwie this.
Po utworzeniu obiektu, wskaźnik this zawiera adres obiektu w pamięci
Wskaźnik pozwala na zidentyfikowanie właściciela danych, do których odwołuje się funkcja składowa
Class Osoba
{ Osoba *this;
Char Nazwisko [50];
Int wiek;
public:
void Czyt_Dane(char*Napis, int Wiek);
void Pisz_Dane()
{cout<<”\t”<<Nazwisko
<<”,lat-”<<Wiek<<endl;}
VIRTUAL
Metoda wirtualna nie może być zadeklarowana jako statyczna (static).
Jeśli metoda wirtualna została zaimplementowana w jakimkolwiek wyższym poziomie dziedziczenia (w szczególności w klasie bazowej całej struktury dziedziczenia), nie jest konieczne podawanie implementacji w klasie pochodnej.
Jeśli w klasie jest zadeklarowana jakakolwiek metoda wirtualna, zaleca się aby destruktor w tej klasie również określić jako wirtualny.
INLINE
Wywołanie funkcji wymaga czasu (kilka instrukcji na poziomie języka maszynowego by przejść w inne miejsce programu). Jest to istotne jeśli funkcje wykonuje się wiele razy. Jeśli funkcja jest krótka (w linii), to w celu przyspieszenia obliczeń używamy funkcji inline.
Deklarujemy i definiujemy ją na początku programu (albo w pliku nagłówkowym). Przy jej wywołaniu kompilator umieści jej treść w miejscu wywołania.
NEW
Funkcja new jest odpowiedzialna za przydzielanie pamięci i zwraca wskaźnik typu void* do jej początku.
17. Klasa abstrakcyjna.
Klasa, która nie reprezentuje żadnego konkretnego obiektu.
Jeśli potrafimy wyodrębnić wspólne cechy i zachowania to możemy zdefiniować klasę abstrakcyjną obiektu, który opisuje to co wspólne. Dzięki temu pewne funkcje definiowane są tylko raz.
Class figura { //klasa abstrakcyjna
protected;
int pozycja_x, pozycja_y, kolor;
public:
Void przesun (int dx, int dy)
{ pozycja_x+=dx;
pozycja_y+=dy;
}
}
Zalety:
Zaoszczędza pracę przy programowaniu, wspólne cechy I zachowanie kilku klas definiujemy jednokrotnie
Umieszczanie szkieletu funkcji a jej implementacje w klasach pochodnych
Deklaruje się funkcje jako virtual
Szablon funkcji
Jest to mechanizm do tworzenia rodziny funkcji identycznych w działaniu, ale różniących się typem argumentów.
template<class j_typ>
j_typ wieksza (j_typ x, j_typ y )
{
Return (x>y)? x: y;
}
main()
{ int a=3300, b=27000;
double x=1.12, y=3.11;
short z=1, f=12;
cout<<”większy z int: ”<<wieksza(a,b) <<endl;
cout<<”większy z double: ”<<wieksza(x,y) <<endl;
cout<<”większy z short: ”<<wieksza(z,f) <<endl;
cout<<”większy z char: ”<<wieksza(‘a’,’b’) <<endl;
while(!kbhit());
}
Zalety:
Oszczędzamy na kodzie programu – jest on bardziej przejrzysty i generuje się automatycznie
W zależności od gtypu argumentów enerowana jest funkcja działająca na tym etapie
Mamy tyle funkcji co różnych typów przy wywołaniu
Funkcja generowana jest tylko raz, mimo powtórzenia.