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 (<workspace>/Shapes).

Dodaj klasę Shape

File→New→C++ class

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 <i i naciśnij CTRL+SPACE.

Klasa Line

Dodaj klasę Line dziedziczącą po Shape: File→New→C++ class . Wybierz klasę bazową…

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<<"<line> <x1>"<<x1<<"</x1> <y1>"<<y1<<"</y1> <x2>"<<x2<<"</x2> <y2>"<<y2<<"</y2> </line>"<<std::endl;
}
 
void Line::move(int dx, int dy) {
	x1+=dx;
	y1+=dy;
	x2+=dx;
	y2+=dy;
}

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 <math.h>
 
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 <list>
class ShapeFactory {
	ShapeFactory();
	virtual ~ShapeFactory();
	static ShapeFactory _theFactory;
	std::list<Shape*>store;
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 <stdlib.h>
#include <time.h>
 
 
ShapeFactory ShapeFactory::_theFactory;
 
ShapeFactory::ShapeFactory() {
	// TODO Auto-generated constructor stub
	srand (time(NULL));
}
 
ShapeFactory::~ShapeFactory() {
	// TODO Auto-generated destructor stub
	for(std::list<Shape*>::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: zlib.zip. Rozpakuj zawartość w podręcznym katalogu.

Utwórz projekt zlib

Utówórz projekt typu static library o nazwie zlib

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.

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:

  1. Powiadomić środowisko, że projekt Shapes jest zależny od artefaktu projektu zlib
  2. Ustawić katalog include tak, aby można było korzystać z funkcji zdefiniowanych w bibliotece zlib
  3. Poinformować linker, gdzie znajduje się plik biblioteczny.

Wszystkie opcje są dostępne po wybraniu Project→Properties

Zależności między projektami

Includes

Wskazanie pliku biblioteki

:!: 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 <sstream>
#include "zlib.h"
 
int main(){
	gzFile out = gzopen("shapes.xml.gz","wb3");
	const char header[]="<?xml version=\"1.0\"?>\n<shapes>\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<<os.str();
	}
	const char trailer[]="</shapes>";
	gzwrite(out,trailer,strlen(trailer));
	gzclose(out);
	return 0;
}

Po wykonaniu programu powinno powstać archiwum takie, jak to (1.1MB). Jeśli na laboratoryjnym komputerze program działa nieco za długo, proponuję zmniejszyć liczbę wygenerowanych obiektów…

swo/lab_1_eclipse_i_cdt.txt · Last modified: 2022/01/17 13:05 by pszwed
CC Attribution-Share Alike 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0