====== Rozwijanie programu w języku C++ w środowisku Eclipse i CDT ====== ===== Część pierwsza: tworzymy program od podstaw ===== ==== Nowy projekt ==== Utwórz nowy projekt i nazwij go //Shapes//. Pliki projektu zostaną umieszczone w standardowym folderze roboczym (///Shapes//). {{:swo:swo-1-shapes-project.png?500}} ==== Dodaj klasę Shape ==== //File->New->C++ class// {{:swo:swo-1-shape-class.png?500}} Dodaj trzy metody (tzn. wpisz w edytorze)... class Shape { public: Shape(); virtual ~Shape(); virtual void write(std::ostream&os)=0; virtual double area(){return 0;}; virtual void move(int dx,int dy){} }; Aby usunąć ikonę błędu przy ''virtual void write'' zacznij pisać ''#include New->C++ class// . Wybierz klasę bazową... {{:swo:swo-1-circle-class.png?400}} Na rysunku jest ''Circle'' - będzie następna... Następnie dodaj atrybuty i metody w pliku nagłówkowym, jak w przykładzie.... class Line: public Shape { public: Line(); virtual ~Line(); int x1,y1,x2,y2; void write(std::ostream&os); void move(int dx,int dy); }; *Wybierz //Source->Implement methods// i zaznacz, że chcesz dodać metody ''write'' i ''move'' i wpisz kod do wygenerowanych szkieletów funkcji #include "Line.h" Line::Line() { // TODO Auto-generated constructor stub x1=y1=x2=y2=0; } Line::~Line() { // TODO Auto-generated destructor stub } void Line::write(std::ostream& os) { os<<" "< "< "< "< "< **W tym momencie warto przekompilować**: //Project->Build Project//. Jeśli są jakieś błędy - zastanów się dlaczego i usuń je... ==== Klasy Circle i Rectangle ==== W analogiczny sposób dodaj klasy ''Circle'' i ''Rectangle'' z atrybutami i metodami, jak poniżej... #include "Shape.h" #include class Circle: public Shape { public: Circle(); virtual ~Circle(); int x; //center x int y; //center y int r; //radius void write(std::ostream&os); virtual double area(){return M_PI*r*r;}; virtual void move(int dx,int dy){x+=dx;y+=dy;} }; #include "Shape.h" class Rectangle: public Shape { public: Rectangle(); virtual ~Rectangle(); int x1,y1,x2,y2; void write(std::ostream&os); double area(); void move(int dx,int dy); }; ==== Fabryka kształtów ==== Zdefiniujemy klasę, która będzie generowała kształty na żądanie (i na dodatek zapamiętywała do nich wskaźniki, aby nie bawić się w zwalnianie pamięci). W programie będzie potrzebna tylko jedna instancja klasy, zastosujemy więc wzorzec projektowy //Singleton//. Dodaj więc nową klasę ''ShapeFactory'' i uzupełnij jej nagłówek w podany poniżej sposób. #include "Shape.h" #include class ShapeFactory { ShapeFactory(); virtual ~ShapeFactory(); static ShapeFactory _theFactory; std::liststore; public: static ShapeFactory&get(){return _theFactory;} Shape*createLine(int x1,int y1,int x2,int y2); Shape*createCircle(int x,int y,int r); Shape*createRectangle(int x1,int y1,int x2,int y2); Shape*createRandomShape(); // tworzy losowo wybrany wektor z losowymi atrybutami }; Następnie, jak poprzednio wybierz opcję //Source->Implement methods// i uzupełnij kod zgodnie ze wzorcem. W kodzie brakuje ''#include'' i implementacji niektórych metod. Pisząc je, możliwie często posługuj się podpowiedziami (zacznij pisać i użyj CTRL+SPACE). #include "ShapeFactory.h" #include #include ShapeFactory ShapeFactory::_theFactory; ShapeFactory::ShapeFactory() { // TODO Auto-generated constructor stub srand (time(NULL)); } ShapeFactory::~ShapeFactory() { // TODO Auto-generated destructor stub for(std::list::iterator i=store.begin();i!=store.end();++i){ if(*i!=0)delete *i; } } Shape* ShapeFactory::createLine(int x1, int y1, int x2, int y2) { Line*s= new Line(); s->x1=x1; s->x2=x2; s->y1=y1; s->y2=y2; store.push_back(s); return s; } Shape* ShapeFactory::createCircle(int x, int y, int r) { //... } Shape* ShapeFactory::createRectangle(int x1, int y1, int x2, int y2) { //... } Shape* ShapeFactory::createRandomShape() { int choice = rand()%3; switch(choice){ case 0: return createLine(rand()%300,rand()%300,rand()%800,rand()%900); case 1: return createCircle(rand()%900,rand()%900,rand()%300); case 2: return createRectangle(rand()%300,rand()%300,rand()%800,rand()%900); } return 0; } ==== Testujemy ==== W pliku //Shapes.cpp// wprowadź następującą fukcję ''main()'' i uruchom program... int main() { for(int i=0;i<100;i++){ Shape*s=ShapeFactory::get().createRandomShape(); s->write(cout); } return 0; } ==== Dla wytrwałych i purystów==== Jeśli lubisz opakowywać atrybuty metodami dostępu typu ''set()'' i ''get()'', wybierz //Source->Generate Getters and Setters//. Nie jest to jednak refaktoryzacja. Funkcja nie potrafi zmienić atrybutów na prywatne i odpowiednio zmodyfikować wywołań. ===== Część druga: korzystamy z gotowej biblioteki ===== Pobierz kod źródłowy biblioteki //zlib// ze strony [[http://www.zlib.net/]]. Jest też w wersji przyciętej do kluczowych plików dostępna tu: {{:swo:zlib.zip|zlib.zip}}. Rozpakuj zawartość w podręcznym katalogu. ==== Utwórz projekt zlib ==== Utówórz projekt typu //static library// o nazwie //zlib// {{:swo:swo-1-zlib-library.png?400}} ==== Zaimportuj pliki ==== Wybierz opcję //File->Import->General[File system]// i zaznacz pliki //*.c// oraz //*.h// z głównego katalogu, w którym rozpakowane zostało archiwum z zlib. Zostaną one skopiowane do folderu projektu. {{:swo:swi-1-import-files.png?400}} ==== Skompiluj ==== Wybierz //Project->Build Project//. Wówczas w podkatalogu //Debug// powinien zostać utworzony plik biblioteki o nazwie //libzlib.a//. * Nazwę można ustalić w //Project->Properties->C/C++ Build->Settings->Build Artifact// * Aby utworzyć wersję //Release// należy zmienić aktywną konfigurację. ===== Część trzecia: łączymy Shapes z zlib ===== ==== Konfiguracja ==== Musimy: - Powiadomić środowisko, że projekt //Shapes// jest zależny od artefaktu projektu //zlib// - Ustawić katalog //include// tak, aby można było korzystać z funkcji zdefiniowanych w bibliotece //zlib// - Poinformować linker, gdzie znajduje się plik biblioteczny. Wszystkie opcje są dostępne po wybraniu //Project->Properties// ===Zależności między projektami=== {{:swo:swo-1-project-references.png?400}} ===Includes=== {{:swo:swo-1-includes.png?400}} ===Wskazanie pliku biblioteki=== {{:swo:swo-1-libraries.png?400}} :!: **Teraz należy przekompilować projekt** :!: ==== Zmieniamy funkcję main ==== Teraz w funkcji ''main()'' będziemy losowo generować kształty i zapisywać je do skompresowanego pliku w formacie //gz//. #include .... #include #include "zlib.h" int main(){ gzFile out = gzopen("shapes.xml.gz","wb3"); const char header[]="\n\n"; gzwrite(out,header,strlen(header)); for(int i=0;i<100000;i++){ ostringstream os; Shape*s=ShapeFactory::get().createRandomShape(); s->write(os); gzwrite(out,os.str().c_str(),os.str().length()); //cout< Po wykonaniu programu powinno powstać archiwum takie, jak {{:swo:shapes.xml.gz| to (1.1MB)}}. Jeśli na laboratoryjnym komputerze program działa nieco za długo, proponuję zmniejszyć liczbę wygenerowanych obiektów...