Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?
Autor: Piotr Szawdyński
Późniejsze modyfikacje: 'Dante'
Kurs C++

Przestrzenie nazw

[lekcja] Omówienie zagadnienia związanego z przestrzeniami nazw.

Składnia przestrzeni nazw

Do tej pory mieliśmy okazję tylko korzystać z przestrzeni nazw takich jak: std:: i ddt::console::. Teraz pokażę Ci, jak się tworzy własne przestrzenie nazw. Składnia jest bardzo prosta i wygląda następująco:
C/C++
namespace twoja_nazwa
{
    //tutaj możemy tworzyć funkcje, struktury i zmienne
}

Przykład

C/C++
#include <iostream>
#include <conio.h>
using namespace std;

namespace jakasNazwa
{
    struct daneST
    {
        int liczba;
        char znak;
    };
    int dodaj( int a, int b )
    {
        return( a + b );
    }
}
int main()
{
    jakasNazwa::daneST dane;
    dane.liczba = 344;
    dane.znak = 'a';
    cout << "dane.liczba=" << dane.liczba << endl;
    cout << "dane.liczba+22=" << jakasNazwa::dodaj( dane.liczba, 22 ) << endl;
    {
        using namespace jakasNazwa;
        daneST zmienna;
        zmienna.liczba = 13;
        cout << "zmienna.liczba=" << zmienna.liczba << endl;
        cout << "zmienna.liczba+43=" << dodaj( zmienna.liczba, 43 ) << endl;
    }
    getch();
    return( 0 );
}

Ustrzec się błędów

C/C++
//Błędy podczas tworzenia przestrzeni nazw
#include <iostream>
#include <conio.h>
// Nasza przestrzeń nazw
namespace jakasNazwa
{
    struct daneST
    {
        int liczba;
        char znak;
    };
    int zmienna = 2;
    int dodaj( int a, int b )
    {
        return( a + b );
    }
}
// ----------------------
int main()
{
    using std::cout;
    using std::cin;
    using std::endl;
   
    jakasNazwa::daneST dane;
   
    int zmienna = 10;
   
    dane.liczba = 344;
    dane.znak = 'a';
    cout << "dane.liczba=" << dane.liczba << endl;
    cout << "dane.liczba+22=" << jakasNazwa::dodaj( dane.liczba, 22 ) << endl;
    //blok danych1
    {
        using namespace jakasNazwa;
        daneST zmienna;
        zmienna.liczba = 13;
        cout << "zmienna.liczba=" << zmienna.liczba << endl;
        cout << "zmienna.liczba+43=" << dodaj( zmienna.liczba, 43 ) << endl << endl;
    }
    //blok danych2
    {
        /*      daneST zmienna; -> błąd kompilator nie wie co to jest -
            error: `daneST' was not declared in this scope */
        using jakasNazwa::zmienna;
        cout << zmienna;
    }
    cout << "\n\n"
    << zmienna;
    cout << "\n\n"
    << jakasNazwa::zmienna;
    getch();
    return( 0 );
}
W przykładzie użyliśmy bloków. Użycie bloku powoduje, że użyte w nim dane przestają istnieć po jego zakończeniu. Można by powiedzieć, że blok jest traktowany jak funkcja i na takich samych zasadach. Każda zmienna użyta w bloku, istnieje tylko w obrębie tego bloku, czyli czas życia zmiennych i ich zasięg ograniczone są tym blokiem. Czyli nawiasami {  } określającymi zasięg bloku.
Następnie wyświetlamy wartość zmiennej, ponieważ w bloku tym użyliśmy naszej przestrzeni nazw(using jakasNazwa::zmienna;), dlatego instrukcja cout << zmienna; pokazuje nam wartość 2. Mówimy tutaj o przesłonięciu zmiennej int zmienna = 10;(zmiennej lokalnej main). Ponownie wyświetlamy zmienną cout << zmienna; i otrzymujemy 10.
Możemy również dzięki operatorowi zasięgu :: odwołać się do zmienne zawartej w naszej przestrzeni nazw jakasNazwa::zmienna;. Należy pamiętać o zasadach zasięgu zmiennych.
Kolejnym aspektem, na który chce byś zwrócił uwagę to zapisy:
C/C++
int main()
{
    using std::cout;
    using std::cin;
    using std::endl;
   
    jakasNazwa::daneST dane;
Powinieneś w niektórych wcześniejszych kursach zauważyć pewną zmianę związaną ze sposobem podpinania przestrzeni nazw using namespace std; . Celowo wprowadzałem te zmiany by przygotować Cię na lepsze wykorzystanie mechanizmów przestrzeni nazw. Praktycznie od tego kursu powinieneś zaprzestać używania zapisu using namespace std; . Do tej pory stosowaliśmy ten zapis żeby ułatwić naukę i nie obciążać Cię dodatkowymi informacjami. Użycie using namespace std; powoduje zaimportowanie wszystkich dostępnych nazw jakie posiada język C++. Jest to pewnego rodzaju pójście na skróty i wygodnictwo.
Lepszym rozwiązaniem jest importowanie tych przestrzeni nazw, które są nam niezbędne do napisania poprawnie działającej aplikacji. Dlatego zamiast importować wszystkie nawet te nie potrzebne nazwy przestrzeni nazw, stara się wybrać tylko te, które są Ci potrzebne do poprawnego napisania programu.

Przykłady optymalnego zastosowania przestrzeni nazw

Będziemy teraz korygować zadania, które ukazały się do tej pory w kursie
Lekcja 3. - Komentarze - by kod przyjazny był każdemu z Nas
C/C++
/* To jest komentarz, który
zajmuje kilka linii.
Komentarz nie wpływa na działanie programu.
Jest on pomijany przez kompilator. */
#include <iostream> // deklaracja przestrzeni nazw
#include <conio.h> //biblioteka nie obsługująca przestrzeni nazw
//To jest komentarz, który trwa tylko jeden wiersz!!
int main()
{
    // udostępnienie nazw z przestrzeni std
    using std::cout;
    using std::endl;
   
    //Poniższy wiersz wyświetla ciąg znaków zawarty w podwójnych apostrofach
    cout << "Odwiedz nasza strone: http://ddt.pl";
    cout << endl; //Przejście kursora na początek następnego wiersza
   
    //Tak można wypisywać dane jednym cout'em
    cout << "To jest kolejny wiersz z informacja"
    << endl
    << endl << "Nacisnij klawisz aby zamknac program";
   
    getch(); //Czekaj na dowolny znak z klawiatury
   
    return( 0 );
}
Podpięcie biblioteki(#include <iostream>) powoduje deklarację nazw wykorzystywanych w tej bibliotece w przestrzeni nazw std, dzięki temu możemy wykorzystać te metody, które dana biblioteka oferuje. Oczywiście wcześniej je udostępniając
C/C++
// udostępnienie nazw z przestrzeni std
using std::cout;
using std::endl;
 
lekcja 2. - Twój pierwszy projekt
C/C++
#include <iostream> //deklaracja nazw
#include <conio.h>
int main()
{
    std::cout << "Hello world!" << std::endl;
   
    getch();
    return 0;
}
Gdy mamy do czynienia z małym kodem, gdzie nie wykorzystujemy często danych metod biblioteki, wtedy korzystniej jest dostać się bezpośrednio do metod biblioteki, bez udostępniania jej metod.
Pozostaje zapytać czy biblioteka #include <conio.h> także udostępniana jest w przestrzeni nazw? Odpowiedz brzmi nie. Ponieważ biblioteki, które posiadają rozszerzenie .h nie posiadają implementacji przestrzeni nazw.
Tutaj jedna uwaga, co nie znaczy, że ty nie możesz stworzyć takiego pliku.
 
Lekcja 4. - Liczby całkowite - int, short i long
C/C++
//dyrektywy preprocesora------------------------------------
#include <iostream>
#include <conio.h>
#include <climits>
//główny blok programu -------------------------------------
int main()
{
    using std::cout;
    using std::endl;
   
    int max_int = INT_MAX;
    short max_short = SHRT_MAX;
    long max_long = LONG_MAX;
   
    //wyświetlenie maksymalnej wartości typów
    cout << "Maksymalna wartosci int: " << max_int
    << endl
    << "Maksymalna wartosci short: " << max_short
    << endl
    << "Maksymalna wartosci long: " << max_long
    << endl;
    getch();
    return 0;
}
//----------------------------------------------------------

Zagnieżdżanie przestrzeni nazw i ich zastosowanie

Przyjrzyjmy się dokładniej jak możemy wykorzystać przestrzenie nazw do własnych celów.
C/C++
//Zagnieżdżanie przestrzeni nazw-----------------
#include <iostream>
#include <conio.h>
namespace stala
{
    const double PI = 3.14;
    const short MIESIACE = 12;
}
namespace pole_figur
{
    double kolo( const double PI, short r )
    { return( PI * r * r ); }
}
namespace algorytm
{
    using namespace stala;
    double wynik = PI * MIESIACE;
   
}
//główny blok programu -----------------------------
int main()
{
    using std::cout;
    using std::endl;
    //użycie własnych przestrzeni nazw
    using namespace algorytm;
   
    double r; //promień koła
   
    //wyświetlenie------------------------------------
    cout << "Wynik algorytmu = " << wynik
    << endl
    << "Podaj promien kola - ";
    //bezpośredni dostęp do metody cin z std(biblioteki iostream)
    std::cin >> r;
    //bezpośredni dostęp do metody kolo z pole_figur
    cout << "Pole kola = " << pole_figur::kolo( PI, r )
    << endl;
   
    getch();
    return 0;
}
Mam nadzieje, że przykład jest jasny. Na uwagę zasługuję jednak kilka faktów:
  • w przestrzeniach nazw możemy używać innych przestrzeń nazw,
  • możemy również zagnieżdżać tworzone przestrzenie nazw np.
C/C++
namespace jeden
{
    namespace dwa
    {
        namespace trzy
        {
        }
    }
}

Kiedy warto stosować przestrzenie nazw

  • Mogą zastąpić zmienne i statyczne zmienne globalne,
  • gdy tworzymy bibliotekę funkcji i klas,
  • tworząc większy projekt powinniśmy dokładniej przyjrzeć się temu zagadnieniu i wykorzystać jego plusy.
Należy jednak pamiętać by na siłę nie próbować stosować przestrzeni nazw, maja one pomóc nam w programowaniu. Jeśli więc tworzysz przestrzenie nazw to zastanów, by nie popełnić błędów.

Ćwiczenia

1. Skoryguj następujące zadania z poprzednich lekcji:
  • Wykorzystanie struktury w praktyce,
  • Tablice struktur,
  • Pozostałe funkcje, wykorzystywane podczas pracy z plikami,
  • Funkcji a tablice,
usuwając z nich linijkę using namespace std; i zastosuj odpowiednie mechanizmy przestrzeni nazw.
Poprzedni dokument Następny dokument
Funkcje raz jeszcze Dzielenie kodu na kilka plików źródłowych