Przypomnienie ...
(język C++)
referencje
Wykład 2.
Tomasz Marks - Wydział MiNI PW
-1-
Tomasz Marks - Wydział MiNI PW
-2-
Referencje (1)
int Num = 50;
zdefiniowano zmienną Num
(typu int ) nadają c jej wartość począ tkową 50.
• Referencja (odnośnik) jest zmienną identyfikującą inną zmienną.
int& Ref = Num;
zdefiniowano zmienną Ref
• Wykonanie operacji na referencji ma taki sam
(typu referencja do int ) i skojarzono ją ze skutek, jak wykonanie tejże operacji na zmiennej zmienną Num .
identyfikowanej przez tę referencję.
Np.
Ref++;
inkrementacja zmiennej Ref ,
int Num = 50;
toż sama z inkrementacją zmiennej Num .
int& Ref = Num;
Ref++;
cout << Num << Ref;
// 51 51
cout << Ref << Num;
zmienne Ref i Num ,
to faktycznie ta sama zmienna.
Tomasz Marks - Wydział MiNI PW
-3-
Tomasz Marks - Wydział MiNI PW
-4-
UWAGA:
{
int n1, n2;
int &ref = n1;
Zabrania się konstruowania deklaracji:
n1 = 10; n2 = 20;
cout << n1 << n2 << ref;
// 10 20 10
referencja-do-referencji // int && ref
ref = n2; n2 = 30;
wskazanie-referencji // int &* ptr
cout << n1 << n2 << ref;
// 20 30 20
tablica-referencji // int & arr[5]
ref = ref + 3;
cout << n1 << n2 << ref;
// 23 30 23
}
Tomasz Marks - Wydział MiNI PW
-5-
Tomasz Marks - Wydział MiNI PW
-6-
Referencje (2)
Referencje (3)
• Parametr funkcji może być określony jako referencja.
• Referencja może być inicjowana stałą. Wymaga się wtedy, aby definiowana zmienna była określona jako W takim przypadku odpowiedni argument wywołania
referencja do zmiennej ustalonej.
funkcji musi być wyrażeniem określającym zmienną
odpowiedniego typu – nie może być n.p. sumą zmiennych.
• W takim przypadku tworzona jest zmienna
N.p.
tymczasowa inicjowana wartością stałej i wszystkie odwołania do zmiennej referencyjnej kierowane są void fun( double& x );
do tej zmiennej tymczasowej.
double a, b;
.....................
Np.
const int &Ref = 50;
fun( a ); // O.K.
cout << Ref;
// 50
fun( a + b ); // Źle !!!
Ref = 33;
// BŁĄD: próba modyfikacji zmiennej ustalonej Tomasz Marks - Wydział MiNI PW
-7-
Tomasz Marks - Wydział MiNI PW
-8-
• Rezultat funkcji może być referencją – wtedy parametry
identyfikuje zmienn
definicji funkcji
ą określoną w instrukcji powrotu
(return).
• Wywołanie funkcji zwracającej referencję może wystąpić wszędzie tam, gdzie może wystąpić nazwa argumenty
zmiennej, a wi
wywołania funkcji
ęc np. jako:
- lewy argument operacji przypisania (=),
- prawy argument op. wprowadzania (>>),
- argument operacji utworzenia wskazania (&)
Tomasz Marks - Wydział MiNI PW
-9-
Tomasz Marks - Wydział MiNI PW
-10-
Sekwencja wymiany wartoś ci 2 zmiennych
UWAGA:
{
int a, b;
W języku C++, w obrębie bloku deklaracje
a = 2;
mogą się przeplatać z instrukcjami.
b = 5;
Ale ...
// teraz chcemy zamienić wartości
// pomiędzy zmiennymi a i b
(1) deklaracja zmiennej musi poprzedzać jej użycie
int tmp;
( tak jak w języku C ),
tmp = a; a = b; b = tmp;
(2) deklaracja nie może być "przeskakiwana".
cout << a << b; // 5 2
...................................
Tomasz Marks - Wydział MiNI PW
-11-
Tomasz Marks - Wydział MiNI PW
-12-
Funkcja C/C++ (zła) zamieniają ca wartoś ci zmiennych Funkcja C/C++ (zła) zamieniają ca wartoś ci zmiennych void exchg1 ( int i, int j )
int a = 2, b = 5;
{
int tmp;
exchg1 ( a, b );
tmp = i; i = j; j = tmp;
}
// jest równoważne realizacji bloku:
{
…………………..
int i = a, j = b;
int a = 2, b = 5;
int tmp;
exchg1 ( a, b );
tmp = i; i = j; j = tmp;
cout << a << b;
// 2 5
}
cout << a << b;
// 2 5
Tomasz Marks - Wydział MiNI PW
-13-
Tomasz Marks - Wydział MiNI PW
-14-
Funkcja C/C++ (dobra) zamieniają ca wartoś ci zmiennych Funkcja C/C++ (dobra) zamieniają ca wartoś ci zmiennych void exchg2 ( int *i, int *j )
int a = 2, b = 5;
{
int tmp;
exchg2 ( &a, &b );
tmp = *i; *i = *j; *j = tmp;
}
// jest równoważne realizacji bloku:
{
…………………..
int *i = &a, *j = &b;
int a = 2, b = 5;
int tmp;
exchg2 ( &a, &b );
tmp = *i; *i = *j; *j = tmp;
cout << a << b;
// 5 2
}
cout << a << b;
// 5 2
Tomasz Marks - Wydział MiNI PW
-15-
Tomasz Marks - Wydział MiNI PW
-16-
Funkcja C++ (dobra) zamieniają ca wartoś ci zmiennych Funkcja C++ (dobra) zamieniają ca wartoś ci zmiennych void exchg3 ( int &i, int &j )
int a = 2, b = 5;
{
int tmp;
exchg3 ( a, b );
tmp = i; i = j; j = tmp;
}
// jest równoważne realizacji bloku:
{
…………………..
int &i = a, &j = b;
int a = 2, b = 5;
int tmp;
exchg3 ( a, b );
tmp = i; i = j; j = tmp;
cout << a << b;
// 5 2
}
cout << a << b;
// 5 2
Tomasz Marks - Wydział MiNI PW
-17-
Tomasz Marks - Wydział MiNI PW
-18-
Do zapamiętania…
• Parametr funkcji jest jej zmienną lokalną
zainicjowaną argumentem wywołania
funkcji.
Przypomnienie ... c.d.
• Jeżeli parametr jest referencyjny, to
operacje dokonywane na parametrze
dotyczą skojarzonego z nim argumentu.
Tomasz Marks - Wydział MiNI PW
-19-
Tomasz Marks - Wydział MiNI PW
-20-
• W języku C jest niedopuszczalne!
Nazwy funkcji muszą być unikatowe.
przeciążanie
int Sum ( int a, int b ) { return a+b; }
int Sum3 ( int a, int b, int c ) { return a+b+c; }
nazw funkcji
double SumD ( double a, double b ) { return a+b; }
……………………
int i, j, k, m, n;
double x, y, z;
n = Sum ( i, j );
m = Sum3 (i, j, k );
z = SumD ( x, y );
Tomasz Marks - Wydział MiNI PW
-21-
Tomasz Marks - Wydział MiNI PW
-22-
Przeciążanie nazw funkcji (2)
Przeciążanie nazw funkcji (3)
• W języku C++ jest dopuszczalne
• Ale uwaga! Jeżeli kompilator "widzi" 2 funkcje i bardzo często wykorzystywane.
int Sum ( int a, int b ) { return a+b; }
int Sum ( int a, int b ) { return a+b; }
double Sum ( double a, double b ) { return a+b; }
int Sum ( int a, int b, int c ) { return a+b+c; }
……………………
double Sum ( double a, double b ) { return a+b; }
int i, j, k, m, n;
……………………
n = Sum ( i, j );
// O.K.
int i, j, k, m, n;
double x, y, z;
// def. zmiennych po instrukcji !
n = Sum ( i, j );
z = Sum ( x, y );
// O.K.
m = Sum (i, j, k );
z = Sum ( x, i );
// BŁĄD
double x, y, z;
z = Sum ( 123, 55.5 );
// BŁĄD
z = Sum ( x, y );
Tomasz Marks - Wydział MiNI PW
-23-
Tomasz Marks - Wydział MiNI PW
-24-
• Liczba i typy argumentów wywołania funkcji
muszą się dać dokładnie dopasować do liczby i
typów parametrów którejś z zadeklarowanych
funkcji.
domyślne wartości
• Trzeba tu jeszcze wiedzieć, że referencja do
argumentów
TYP jest nieodróżnialna od TYP. Dlatego n.p.
nie można definiować przeciążenia
int Sum ( int a, int b ) { return a+b; }
int Sum ( int &a, int &b ) { return a+b; }
Tomasz Marks - Wydział MiNI PW
-25-
Tomasz Marks - Wydział MiNI PW
-26-
Domyślne wartości argumentów (1)
Domyślne wartości argumentów (2)
W języku C++ zamiast używać przeciążenia Sum
dla 2 i 3 parametrów typu int, wystarczy zdefiniować
W skrajnym przypadku można użyć deklaracji
jedną funkcję
int Sum ( int=0, int=0, int=0 );
int Sum ( int a, int b, int c ) { return a+b+c; }
a następnie posłużyć się deklaracją
……………………
int i, j, k, m, n;
int Sum ( int, int, int=0 );
m = Sum ( i, j, k ); // tyle argumentów ile parametrów
……………………
m = Sum ( i, j );
// równoważne n = Sum ( i, j, 0 );
int i, j, k, m, n;
m = Sum ( i );
// równoważne n = Sum ( i, 0, 0 );
m = Sum (i, j, k );
m = Sum ( );
// równoważne n = Sum ( 0, 0, 0 );
n = Sum ( i, j );
// równoważne n = Sum ( i, j, 0 );
Tomasz Marks - Wydział MiNI PW
-27-
Tomasz Marks - Wydział MiNI PW
-28-
Klasę można definiować używając słowa kluczowego struct DEFINIOWANIE
struct NazwaKlasy
{
KLAS
……………………………………….
.. składowe domyś lnie publiczne ..
……………………………………….
……………………………………….
};
Tomasz Marks - Wydział MiNI PW
-29-
Tomasz Marks - Wydział MiNI PW
-30-
Definiowanie klas (2)
Klasę można definiować używając słowa kluczowego class public
class NazwaKlasy
{
private
……………………………………….
.. składowe domyś lnie prywatne ...
protected
……………………………………….
……………………………………….
};
Tomasz Marks - Wydział MiNI PW
-31-
Tomasz Marks - Wydział MiNI PW
-32-
Definicja klasy CMPLX
struct CMPLX
{
Określenia publiczne, prywatne związane są z pojęciem double Re, Im;
dostępności nazw składowych.
…………………
};
Domyślnie, dla składowych klasy definiowanej z użyciem słowa kluczowego struct przyjmuje się dostęp publiczny jest równoważna definicji
(ma to na celu zapewnienie zgodności z językiem C).
class CMPLX
Domyślnie, dla składowych klasy definiowanej z użyciem
{
słowa kluczowego class przyjmuje się dostęp prywatny.
public:
double Re, Im;
Do jawnego określania dostępności składowych służą
…………………
słowa kluczowe: public, private, protected ( chronione).
};
Są to tzw. specyfikatory dostępności.
Tomasz Marks - Wydział MiNI PW
-33-
Tomasz Marks - Wydział MiNI PW
-34-
Definiowanie klas (4)
Napiszmy definicję klasy CMPLX w nowej wersji
Specyfikatory dostępności składowych klasy:
class CMPLX
public – nazw składowych publicznych mogą używać
{
wszystkie funkcje "widzące" definicję klasy, double Re, Im; // Re, Im są teraz prywatne private – nazw składowych prywatnych mogą używać jedynie metody danej klasy i funkcje zaprzyja
public:
źnione z tą
klasą,
double Abs ( ) const;
protected - nazw składowych chronionych mogą używać void Read ( );
jedynie metody danej klasy i funkcje zaprzyjaźnione z tą
};
klasą, oraz metody i funkcje zaprzyjaźnione klas
pochodnych tej klasy.
Tomasz Marks - Wydział MiNI PW
-35-
Tomasz Marks - Wydział MiNI PW
-36-
Możemy ten problem rozwiązać na kilka sposobów.
W konsekwencji definicja funkcji
(1) uzupełnić definicję klasy CMPLX o prymitywne metody dostępu do pól: class CMPLX
CMPLX Add ( CMPLX a, CMPLX b )
{
……………………….
{
public:
double getRe ( ) const { return Re; }
a.Re += b.Re;
double getIm ( ) const { return Im; }
void setRe ( double re ) { Re = re; }
a.Im += b.Im;
void setIm ( double im ) { Im = im; }
return a;
};
}
i napisać treść definicji funkcji Add w postaci jak niżej CMPLX Add ( CMPLX a, CMPLX b )
{
przestała być poprawna, bo zawiera zabronione
a.setRe ( a.getRe( ) + b.getRe( ) );
a.setIm ( a.getIm( ) + b.getIm( ) );
odwołania do prywatnych pól klasy CMPLX.
return a;
}
Tomasz Marks - Wydział MiNI PW
-37-
Tomasz Marks - Wydział MiNI PW
-38-
(2) uzupełnić definicję klasy CMPLX o 2 metody dostępu do pól wykorzystujące referencje:
class CMPLX
{
……………………….
public:
double& refRe ( ) { return Re; }
double& refIm ( ) { return Im; }
};
friend
i napisać treść definicji funkcji Add w postaci jak niżej CMPLX Add ( CMPLX a, CMPLX b )
{
a.refRe( ) += b.refRe( ) ;
a.refIm( ) += b.refIm( ) ;
return a;
}
_
Tomasz Marks - Wydział MiNI PW
-39-
Tomasz Marks - Wydział MiNI PW
-40-
Nasza definicja klasy CMPLX (nowa)
(3) "Zaprzyjaźnić" funkcję Add z klasą CMPLX:
// cmplx.h
class CMPLX
class CMPLX
{
……………………….
{
……………………….
double Re, Im;
public:
friend CMPLX Add ( CMPLX, CMPLX ); // deklaracja zaprzyjaźnienia void Set (double=0, double=0 );
};
void Read ( );
i pozostawić treść definicji funkcji Add w oryginalnej postaci.
void Write ( ) const;
double Abs ( ) const;
Są jeszcze inne możliwości, ale o nich w tej chwili nie będziemy mówili.
friend CMPLX operator+ ( CMPLX, CMPLX );
};
UWAGA: Położenie deklaracji zaprzyjaźnienia względem specyfikatorów dostępności (public, private, protected) w obrębie definicji klasy nie ma żadnego znaczenia.
_
Tomasz Marks - Wydział MiNI PW
-41-
Tomasz Marks - Wydział MiNI PW
-42-
Główny plik aplikacji (nowy)
// myprog.cpp
#include < iostream >
using namespace std;
#include ”cmplx.h”
int main ( )
{
Koniec wykładu 2.
CMPLX x, y, z;
x.Read ( ); // cin 1.5 2.2
y.Set ( 2.0, 3.0 );
z = x + y;
z.Write( ); // cout [ 3.5, 5.2 ]
}
Tomasz Marks - Wydział MiNI PW
-43-
Tomasz Marks - Wydział MiNI PW
-44-