Klasy w C++ PDF Drukuj Email
Wpisał doctor   
Czwartek, 10. Maj 2007 20:53
Klasy


Wstęp

Pisząc o klasach, piszę tak naprawdę o wspaniałym narzędziu, jakim jest programowanie obiektowe. Programowanie obiektowe jest to nic innego jak metoda pisania programów, która opiera się na obiektach. Ale czym jest ten obiekt? OdpowiedĽ wydaje się prosta. Każdy chyba rozumie to pojęcie. Obiektem może być wszystko: dom, samochód, osoba czy nawet pojedynczy atom. W programowaniu jest podobnie. Mianem obiektu możemy określić każdy abstrakcyjny byt, który zapragniemy utworzyć w pamięci komputera. Zauważ, że programy, które pisałeś do tej pory opierały się na „luĽnych” zmiennych i funkcjach, które nie były z sobą powiązane. Pisanie programu polegało wtedy na definiowaniu ogromnej ilości zmiennych, które potem były jakoś wykorzystywane. To tylko my wiedzieliśmy, że dotyczą tego samego. Było to bardzo niewygodne, ponieważ mogliśmy przez przypadek lub w wyniku niewiedzy wysłać do funkcji oczekującej na promień koła pojemność dysku. Kompilator nie zaprotestuje. Miała być liczba double i jest double. Tylko, że na skutek tego, wynik będzie bezsensowny. Klasy (obiekty) chronią nas przed taką sytuacją, ponieważ dane powiązane są z funkcjami.   Drugą zaletą jest moim zdaniem możliwość odwzorowania jakiegoś rzeczywistego obiektu, np. modelu samochodu. Samochód taki możemy opisać jakimiś zmiennymi odpowiedzialnymi za pojemność silnika, ilość siedzeń, maksymalna ładowność, pojemność baku,  a także czynnościami takimi jak hamowanie, skręcanie czy ruszanie. Powstaje zatem nowy typ danej o nazwie samochód.

Klasa to złożony typ zmiennych, składający się z pól, przechowujących dane, oraz posiadający metody, wykonujące zaprogramowane czynności.

{mospagebreak}
Projekt obiektu

Tak jak w codziennym życiu nie można zbudować domu, samochodu bez stworzonego wcześniej obiektu, tak samo jest w C++. Aby utworzyć obiekt, należy go pierw zaprojektować. Taki plan nazywamy właśnie klasą. Określa ona, jak będą zbudowane obiekty tworzone na jej podstawie.
Napisanie definicji klasy nie jest trudne. Składa się ona z słowa kluczowego class, po którym następuje nazwa klasy. Potem piszemy dwie klamry: otwierającą i zamykającą. Zauważ, że po klamrze kończącej stawiamy średnik. Pomiędzy klamrami piszemy ciało klasy. Zobaczmy prosty przykład:

class nazwa_klasy
{
    // tu piszemy ciało klasy

} ; // zauważ średnik !

Stworzenie konkretnego egzemplarza obiektu naszej klasy wygląda tak samo jak tworzenie zmiennej np. typu double. Piszemy najpierw nazwę typu, a następnie nazwę dla konkretnego nowego obiektu. Czyli robimy to tak :

nazwa_klasy duza ; // analogiczne do „double zielona”

Taka definicja powoduje utworzenie w pamięci komputera jednego obiektu naszej klasy. Ma on nazwę duza.
Zatem mamy już za sobą podstawy tworzenia klas. Jak widzisz nie jest to trudne J
    {mospagebreak}
Pierwsza klasa

Wiemy już, jak powinna wyglądać definicja klasy. Nasza poprzednia klasa była pusta, czyli nie zawierała żadnych składników. Składniki mogą być różnego typu. Począwszy od zmiennych typu int a kończąc na tablicach, wskaĽnikach czy nawet obiektach innych klas. Składnikami mogą być także funkcje.

Przykładowa definicja:

class punkt
{
public:
   int x ;
   int y ;
} ;



Pora to wytłumaczyć. Użyte słowo public tworzy grupę składników, które mogą być używane z wnętrza klasy, a także spoza jej zakresu. Czyli możemy się do nich odnosić bez ograniczeń. Wrócimy do tego jednak póĽniej. Dalej widzimy definicję dwóch zmiennych typu int, które będą przechowywać jakieś współrzędne danego punktu. Dodam jeszcze, że te spacje dodane przed zmiennymi mają tylko funkcję estetyczną, bo jak pamiętasz białe znaki przez kompilator są ignorowane.

Jeśli w programie zapragniemy odwołać się do składowych obiektu ( w naszym przykładnie mamy dwie składowe int), na przykład chcemy odczytać lub zapisać jakoś wartość stosujemy jeden z dwóch sposobów:
obiekt.składnik
wskaĽnik_do_obiektu->składnik
{mospagebreak}
Pokażę przykład:

punkt nowy ; // tworzymy nowy egzemplarz obiektu
punkt *wskaznik ; // tworzymy wskaĽnik do pokazywania na konkretne
                  // obiekty naszej klasy                                                 

nowy.x = 100 ; // odniesienie się do składnika x sposobem normalnym
nowy.y = 200 ; // odniesienie się do składnika y sposobem normalnym

wskaznik = &nowy ; // ustawiamy nasz wskaĽnik na konkretny obiekt
wskaznik->x = 100 ; // odniesienie się do składnika x wskaĽnikiem
wskaznik->y = 200 ; // odniesienie się do składnika y wskaĽnikiem
Każda z metod ma swoich zwolenników. Czasem zachodzi jednak potrzeba użycia jednej metody, a nie drugiej. Ale decyzja o tym, w którym momencie i jakiej metody użyjesz zależy już tylko od Ciebie.
 

Rodzaje etykiet

Etykiety służą do ukrywania bądĽ odsłaniania pewnych zmiennych, funkcji. Jedną etykietę już poznałeś. Była to etykieta public. Składniki, które znajdują się pod tą etykietą są publiczne, czyli mogą być używane z wnętrza klasy jak i spoza zakresu klasy.
Mamy jeszcze dwie inne etykiety : private i protected. Etykieta private służy do ukrycia pewnych składników. Oznacza to, że deklarowane za nią składniki są dostępne tylko z wnętrza klasy. Pewnie zastanawiasz się jak dotrzeć do takich danych składowych, skoro są one niedostępne spoza zakresu klasy. Otóż wtedy trzeba się posłużyć jakąś funkcją składową, lecz o tym dalsze rozdziały.
Etykietą protected w tym kursie nie będziemy się zajmować, bo to już inna bajka.



Etykiety można umieszczać w dowolnej kolejności, mogą się też powtarzać. Zobaczmy przykład :

#include <iostream>
using namespace std ;

class samochod
{
private:
  int ilosc_srub ;
public:
  double pojemnosc ;
  long ilosc_siedzen ;
} ;

int main()
{
  samochod nowy ; // tworzymy konkretny obiekt

  // teraz będziemy się odnosić do składników

  nowy.ilosc_srub = 5 ; // BَD. Składnik ilość_srub jest przecież
                        // prywatny. Nie możemy się do niego odnieść
                       // bo znajdujemy się poza zakresem klasy.           
  nowy.pojemnosc = 1.6 ; // OK. Wszystko w porządku. Składnik ten
                         // jest publiczny.
  nowy.ilosc_siedzen = 5 ; // OK. Wytłumaczenie jak wyżej.

  cout << „Ilosc siedzen wynosi : „ << nowy.ilosc_siedzen << endl ;
 
  system(„pause”) ;  
  return 0 ;
}

Na koniec drobna uwaga. Jeśli nie napiszemy na początku żadnej etykiety to przez domniemanie składniki są prywatne. Czyli :

class punkt
{
   int polozenie ; // te składniki są prywatne, bo nie nastąpiła
   double costam ; // żadna etykieta
public: // tu następuje etykieta
  int x ; // te są już publiczne
  int y ;
} ;

Mamy możliwość także takiego zapisu :

class punkt
{
  int polozenie ; // prywatne
  long jakas_liczba ; // ten tez prywatny
public:
   int x, y ; // te dwa są już publiczne
private :
   long double duza_liczba ; // znowu prywatny
} ;

Tego sposobu nie polecam, bo co nam to daje. Tylko zagmatwamy sobie kod. Musimy potem szukać, które składniki były prywatne, a które publiczne. Przyjęła się taka zasada, że na początku piszemy składniki prywatne, a następnie publiczne, które są tak jakby najpotrzebniejsze programiście.
{mospagebreak}
Funkcje składowe

Klasa może mieć także funkcje składowe, których zwykle używamy do pracy z składnikami klasy. Z poprzedniego rozdziału o etykietach wiesz, że niektóre składniki mogą być prywatne. Do tych składników mają dostęp tylko inne składniki tej klasy, a zatem między innymi funkcje składowe. W wnętrzu takich funkcji możemy wywoływać inne funkcje, odnosić się do zmiennych składowych, bądĽ do zmiennych globalnych (osobiście nie polecam) . Funkcje składowe wywołujemy na rzecz konkretnego obiektu danej klasy. Identycznie było przy odnoszeniu się od zmiennych składowych - najpierw pisaliśmy nazwę konkretnego obiektu klasy, a potem nazwę konkretnej zmiennej.

No to nadszedł czas na przykład :

class uczen
{
   string imie ;
   double srednia ;
public:
   void wpisz(string name, double sr) ; // funkcja składowa
   double podaj_srednia(void) ; // druga funkcja skladowa
} ;

Widzimy tu dwie deklaracje funkcji składowych. Ale są to tylko deklaracje. Musimy je gdzieś teraz zdefiniować. Są dwa sposoby definiowania funkcji składowej : wewnątrz klasy lub na zewnątrz klasy.

Sposób 1 :
Definicja wewnątrz klasy.

class uczen
{
   string imie ;
   double srednia ;
public:
   void wpisz(string name, double sr)
   {
     imie = name ;
     srednia = sr ;
   }
   double podaj_srednia(void)
   {
      return srednia ;
   }     
} ;

Te funkcje nic ciekawego nie robią. Jedna zapisuje podane jej dane, druga podaje nam średnią ucznia.  

Sposób 2:
Definicja na zewnątrz klasy.

class uczen
{
   string imie ;
   double srednia ;
public:
   void wpisz(string name, double sr) ;
   double podaj_srednia(void) ;
} ;

void uczen::wpisz(string name, double sr)
{
     imie = name ;
     srednia = sr ;
}
double uczen::podaj_srednia(void)
{
  return srednia ;
}  
   

Jak widać w drugim przypadku funkcja znajduje się poza definicją klasy, a zatem trzeba dopisać nazwę klasy, z której ta funkcja pochodzi. Do tego służy operator zakresu, czyli dwa dwukropki :: .
Pomyślisz : po co aż dwa sposoby ? Otóż jest między nimi pewna drobna różnica. Polega ona na tym, że jeśli zdefiniujemy funkcję w obrębie klasy jest ona typu inline, a jeśli poza klasą to jest wtedy najzwyklejszą funkcją. Wybór znowu należy do Ciebie.  Pamiętaj jednak, że długa funkcja zdefiniowana w wnętrzu klasy nie wygląda zbyt ładnie. Sprawia to, że kod jest mało przejrzysty. Dłuższe funkcje lepiej definiować zatem poza zakresem klasy. A jeśli ktoś lubi bawić się z plikami może klasę podzielić na dwa pliki. W pierwszym pliku (plik H) umieszczamy definicję klasy z deklaracjami funkcji, a w drugim pliku (plik CPP) piszemy definicję funkcji. Pracując w dobrych środowiskach programistycznych mamy łatwą możliwość takiego dzielenia klasy na dwa pliki. Wystarczy przyciśnięcie paru przycisków i gotowe.  
Zaprezentuję jakiś dłuższy przykład :

#include <iostream>
#include <string>
using namespace std ;

class samochod
{
  double pojemnosc ;
  string kolor ;
  string marka ;
  double stan_baku ;

public:
  void zatankuj() ;
  void wpisz_dane(double poj, string color, string typ) ;
  string opis() ;
} ;


void samochod::zatankuj()
{
  stan_baku = 100 ;
}
void samochod::wpisz_dane(double poj, string color, string typ)
{
   pojemnosc = poj ;
   kolor = color ;
   marka = typ ;
}
string samochod::opis()
{
   string dane = "Nasz samochod jest marki " + marka +
                  ", i ma " + kolor + " kolor."  ;
   return dane ;
}

int main()
{
   double silnik ;
   string lakier ;
   string marka ;
   samochod nowy ; // tworzymy obiekt
   cout << "Podaj marke : " ;
   cin >> marka ;
   cout << "Podaj pojemnosc silnika : " ;
   cin >> silnik ;
   cout << "Podaj kolor karoserii : " ;
   cin >> lakier ;

   nowy.wpisz_dane(silnik, lakier, marka) ;
   nowy.zatankuj() ;
   cout << nowy.opis() << endl ;

   system("pause") ;
}

Konstruktory

Konstruktor jest to funkcja składowa klasy, która jest wywoływana automatycznie podczas tworzenia nowego obiektu klasy. Charakteryzuje się on tym, że nazywa się tak samo jak klasa.
Typowym zadaniem konstruktora jest zainicjowanie pól ich początkowymi wartościami,
przydzielenie pamięci wykorzystywanej przez obiekt czy też uzyskanie jakichś kluczowych
danych z zewnątrz.

Konstruktory w przeciwieństwie do funkcji składowych nie zwracają żadnej wartości. Powtarzam żadnej. Nawet void. Po prostu nie stoi przed nim żadna wartość, tylko sama nazwa. Czyli wnioskując, nie może być w nim także instrukcji return zwracająca jakąś wartość.

Oto przykładowy program z klasą wykorzystującą konstruktor :

class uczen
{
   int wiek ;
public :
   uczen(int age) ; // konstruktor
} ;
uczen::uczen(int age) // definicja konstruktora
{
   wiek = age ; // nadanie wartości
}

int main()
{
   uczen nowy(23) ; // tutaj rusza do pracy konstruktor
   return 0 ;
}

Zadaniem tego konstruktora jest nadanie wartości zmiennej wiek. W ciele tego konstruktora jest linijka odpowiedzialna za tą operację.

Zauważ, że konstruktor umieszczony jest w sekcji public. Jak byśmy umieścili go w private, nie mielibyśmy do niego dostępu. Nie możliwa zatem była by instrukcja :
uczen nowy(23) ;

Kompilator wyrzuciłby nam błąd, że nie ma zdefiniowanego takiego konstruktora. Takiego, to znaczy z argumentem typu int (23 jest przecież typu int).

Konstruktory można także przeładowywać, czyli może istnieć kilka konstruktorów różniących się tylko typem i ilością przyjmowanych argumentów. Jest to bardzo częsta praktyka, gdyż najczęściej przy tworzeniu program chcemy mieć możliwość wyboru, w jaki chcemy stworzyć nowy obiekt.



class uczen
{
   int wiek ;
   double srednia ;
public :
   uczen(int age) ;
   uczen(void) ; // konstruktor domniemany
   uczen(int age, double sr) ;
} ;
uczen::uczen(int age)
{
   wiek = age ;
}
uczen::uczen(void)
{
  wiek = 0 ;
  srednia = 0 ;
}

uczen::uczen(int age, double sr)
{
  wiek = age ;
  srednia = sr ;
}

int main()
{
  uczen marek ; // tu działa konstruktor uczen(void)
  uczen adrian(16) ; // tu działa uczen(int age)
  uczen Piotrek(23, 4.6) ; // a tu uczen(int age, double sr)
  return 0 ;
}

To, który konstruktor zostanie uruchomiony, wynika z kolejności i typu argumentów wywołania. W komentarzach podałem jaki konstruktor zostanie wywołany w danej sytuacji.

Na liście konstruktorów pojawia się także konstruktor domniemany. Jest to konstruktor, którego można wywołać bez żadnych argumentów. Taki konstruktor wywołujemy bez podawania w nawiasach żadnych danych. W naszym powyższym przykładzie było to :
uczen marek ;
Jak widzisz nie ma tu nawiasu, w którym wpisujemy dane jakie mają zostać wysłane do konstruktora.
Zastanawia Cie pewnie fakt, że w naszych poprzednich przykładach nie było nigdzie definicji żadnego konstruktora, a mimo to mieliśmy możliwość tworzenia nowych egzemplarzy naszej klasy.
Przypomnę tą sytuację :

class punkt
{
public:
   int x ;
   int y ;
} ;

int main()
{
   punkt nowy ; // !!!
  // ...
}

Na pierwszy rzut oka widać, że nie mamy tu żadnych konstruktorów, a jednak mamy tą możliwość tworzenia nowych obiektów klasy. Dlaczego ??!!
Jeśli nie zdefiniujemy samodzielnie konstruktora domniemanego, kompilator wygeneruję go samodzielnie. Co prawda ten wygenerowany konstruktor jest dla nas nie widoczny, ale możemy z niego korzystać. Kompilator działa więc na naszą korzyść, pomagając nam jak tylko może ;)

Konstruktor domniemany nie zostanie wygenerowany w sytuacji takiej, że mamy zdefiniowany już w klasie jakiś konstruktor (ale nie domniemany). Czyli :

class punkt
{
  int x, y ;
public:
  punkt(int a, int b)
  {
    x = a ;
    y = b ;
  }
} ;

int main()
{
   punkt nowy(3, 4) ; // Ok. Mamy przeciez taki konstruktor.
   punkt nowy2 ; // Błąd. Takiego konstruktora nie mamy.
}

W tym przykładzie otrzymamy błąd kompilacji, ponieważ w ciele klasy nie mamy nigdzie zdefiniowanego konstruktora domniemanego. Kompilator nie wygeneruje nam go za nas, gdyż w ciele klasy mamy już jakiś inny konstruktor. Pomyśli sobie on pewnie tak : „Hmm, widzę tu, że programista zdefiniował sobie jakiś konstruktor, czyli pewnie będzie z niego korzystał. Moja praca jest mu zatem niepotrzebna. Nie wygeneruję mu konstruktora domniemanego. Bo i po co ??? Jak będzie chciał to sam sobie go zdefiniuje”. JJJ
Reasumując. Konstruktor domniemany zostanie wygenerowany tylko wtedy, gdy nie mamy w ciele klasy zdefiniowanego żadnego konstruktora. I tyle.

Na koniec tego rozdziału dodam, że istnieje możliwość także takiego zapisu :
punkt nowy = punkt(3,4) ;
Jest to równoważne z zapisem :
punkt nowy(3, 4) ;

Po prostu w pierwszym przykładzie lepiej widać, że najpierw tworzymy nowy obiekt, a dopiero potem przypisujemy do niego działanie konstruktora. Można stosować wymiennie, kto co lubi.
{mospagebreak}
Destruktory

Destruktor jest przeciwieństwem konstruktora. Jest to nic innego jak funkcja składowa, która zostaje automatycznie wywołana przy likwidacji danego obiektu. Nazywa się tak samo jak klasa, tylko, że przed nawą ma znaczek ~ (tylda). Tak samo jak konstruktor nie zwraca żadnej wartości, nawet void. Destruktor nie może także przyjmować żadnej wartości, czyli nie możemy wysyłać do niego żadnych argumentów. W przeciwieństwie do konstruktora, nie może być przeładowany. Destruktor nie jest konieczny, chodĽ czasem się przydaje ;)

Destruktor nie likwiduje obiektu, ani nie zwalnia obszaru pamięci, który obiekt zajmował. Destruktor przydaje się tylko wtedy, gdy przed zniszczeniem obiektu trzeba jeszcze dokonać jakiś operacji. Po prostu posprzątać.

Obiekty tworzone lokalnie ( w wnętrzu jakiegoś bloku ) likwidowane są przy wyjściu z tego bloku, w którym się znajdują. A obiekty globalne likwidowane są na zakończenie programu.
Jeśli definiujemy jakiś obiekt w funkcji main, to zostaje on zlikwidowany przy zakończeniu programu.

Oto prosty przykład :

#include <iostream>
#include <string>
using namespace std ;

class Kolega
{
  string imie ;
  string adres ;
  int wiek ;
public :
  Kolega() ;
  Kolega(string name, string adress, int age) ;
  void Wypisz() ;
  ~Kolega() ;    // destruktor
} ;


Kolega::Kolega()
{
  imie = "Anonim" ;
  adres = "Brak danych" ;
  wiek = 0 ;
}


Kolega::Kolega(string name, string adress, int age)
{
  imie = name ;
  adres = adress ;
  wiek = age ;
}

void Kolega::Wypisz()
{
  cout << " Nasz kolega nazywa sie : " << imie << endl ;
  cout << " Mieszka w : " << adres << ", i ma " << wiek << " lat." << endl ;
}

Kolega::~Kolega()
{
  cout << " Niszcze obiekt !!!" ;
}

int main()
{
  Kolega Marek("Marek Nowak", "Warszawa", 46) ;
  Marek.Wypisz() ;

  { // otwieram jakis blok
    cout << " >> Otwieram lokalny blok << " << endl ;
    Kolega Anonim ;
    Anonim.Wypisz() ;
    cout << " >> Koncze lokalny blok << " << endl ;
  } // tu nasz kolega ginie, bo konczy sie zakres
  cout << endl ;
  system("pause") ;
  return 0 ;
}

Myślę, że przykład był na tyle dobry, że nie trzeba nic tłumaczyć. W ciele destruktora umieściłem instrukcję odpowiedzialną za wypisanie tekstu, która pomaga nam dostrzec, w którym miejscu i momencie pracuje destruktor.

Destruktor można także wywołać jawnie. Co to oznacza ? Oznacza to, że w dowolnej chwili możemy uruchomić destruktor na rzecz konkretnego obiektu. Robimy to np. wtedy, gdy w ciele klasy mieliśmy kilka instrukcji new, które stworzyły jakieś zmienne zajmujące teraz niepotrzebnie pamięć. Wywołujemy destruktor, w którym znajdują się instrukcje delete zwalniające tą pamięć.   Jawne wywołanie destruktora wygląda tak :

nawa_obiektu.~nazwa_destruktora() ;

Oczywiście jak wiadomo nazwa destruktora jest taka sama jak nazwa klasy, czyli nas zapis może także wyglądać tak :

nazwa_obiektu.~nazwa_klasy() ;


Przesłanie obiektu klasy do funkcji

Czasami zachodzi potrzeba wysłania jakiegoś obiektu klasy do funkcji. Ale nie do funkcji składowej, lecz globalnej. Jeśli nie zdefiniujemy tego inaczej, to domyślnie przesyłanie odbywa się przez wartość.
Zobaczmy prosty przykładzik :

#include <iostream>
#include <string>
using namespace std ;

class Sport
{
  int prywatny ;
public :
  Sport(string name, int ile)
  {
    prywatny = 0 ;
    nazwa = name ;
    liczba_graczy = ile ;
  }
  string nazwa ;
  int liczba_graczy ;
} ;

void Funkcja(Sport zawody) // !!!
{
   cout << "Nasz ulubiony sport to : " << zawody.nazwa ;
   cout << endl << "Wykonywany jest przez " << zawody.liczba_graczy << " graczy" ;
   cout << endl ;
   // cout << zawody.prywatny ; // W tym miejscu byłby błąd
}
int main()
{
  Sport Pilka("pilka nozna", 22) ;
  Funkcja(Pilka) ;
  system("pause") ;
  return 0 ;
}

W miejscu zaznaczonym trzema wykrzyknikami znajduję się definicja funkcji. Nie jest to zwykła funkcja. Spójrz się na jej przyjmowany argument. Jest to przecież obiekt naszej klasy Sport. Funkcja ta, jest wiec funkcją wywoływalną z jednym argumentem typu Sport, a zwracającą typ void.

Zauważ, że funkcje takie nie mają dostępu do składników prywatnych klasy. Są one dla nich niedostępne.

Jak mówiłem na początku rozdziału, przez domniemanie obiekty klasy przesyłane są do funkcji przez wartość. Można przesłać je także przez referencję. Wystarczy tylko zmiana w linijce :

void Funkcja(Sport zawody)

Musimy ją zmienić na :

void Funkcja(Sport &zawody)

Reszta pozostaje bez zmian.

Autor: Tasmman






 







   


Klasa tworzy nowy typ danych.Trzeba sobie uświadomić, że klasa to dane oraz funkcje operujące na tych danych.
Funkcjami które zawsze są obecne w ciele klasy to konstruktor oraz destruktor.
Na przykładzie prostej klasy PudełkoZapałek pokażę, jak stworzyć nową klasę oraz jak ją wykorzystać w programie.

class PudelkoZapalek
{
    private:
    int ile_zapalek;
    public:
    void Dodaj (int ile);
    void Wyjmij (int ile);
}
Komentarze
Dodaj nowy Szukaj
+/-
Napisz komentarz
Nick:
E-mail:
 
Strona www:
Tytuł:
UBBCode:
[b] [i] [u] [url] [quote] [code] [img] 
 
 
:angry::0:confused::cheer:B):evil::silly::dry::lol::kiss::D:pinch:
:(:shock::X:side::):P:unsure::woohoo::huh::whistle:;):s
:!::?::idea::arrow:
 
Proszę wpisać kod antyspamowy widoczny na obrazku.
Anonimowy   |83.23.212.xxx |2009-05-27 16:39:19
Proszę o pomoc w dopisaniu komentarzy w programie....
#include
using namespace
std ;
#include


class gadula
{
int licz ;
char tekst[40] ;
public
:
gadula(int k, const char *opis) ;
~gadula(void) ;
int zwracaj() { return licz
; }
void schowaj(int x) { licz = x ; }
void coto()
{
cout
Anonimowy   |83.23.212.xxx |2009-05-27 16:39:57
#include
using namespace std ;
#include


class gadula
{
int licz ;

char tekst[40] ;
public :
gadula(int k, const char *opis) ;
~gadula(void) ;
int
zwracaj() { return licz ; }
void schowaj(int x) { licz = x ; }
void
coto()
{
cout

3.26 Copyright (C) 2008 Compojoom.com / Copyright (C) 2007 Alain Georgette / Copyright (C) 2006 Frantisek Hliva. All rights reserved."

Ostatnia aktualizacja: Piątek, 10. Lipiec 2009 14:58
 
 

Losowy obraz

b13.jpg

Gościmy

Naszą witrynę przegląda teraz 11 gości 




| | | |