Wer die Details mit xtekplot1 (noch) nicht so genau wissen will kann
das Minmalbeispiel hier
runterladen, den folgenden Abschnitt überspringen und direkt bei
Übung 8 weitermachen.
(Entpacken unter Linux: tar zxvf name.tar.gz
andere Unixe: gunzip name.tar.gz; tar -xvf name.tar)
Hier ein minimales Beispiel um xtekplot1 zu verwenden:
//grafikstart.cc #define VERSION "Version 0.0" #include <stdio.h> #include <stdlib.h> #ifndef GCC_VERSION #define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) #endif #if GCC_VERSION>=3000 #include <iostream> using namespace std; #else #include <stream.h> #endif #ifdef AMIGA #include <amitekplot1.h> #else #include <xtekplot1.h> #endif const int XMAX=640,YMAX=512,TIEFE=4; static int breite,hoehe,tiefe,visklasse; //Globale Variablen static double xmin= -0.1, ymin=0.0, xmax=1.1, ymax=1.0; static int exitflag=0; void menu_exit() {exitflag=1;} void grafik_zeichnen() {plot(0.,0.,PENUP); plot(1.,1.,PENDOWN);} main(int argc,char *argv[]) { //tek_setdebug(1);//test if(argc>1 && *argv[1]=='?') {printf("programmname %s\n",VERSION); exit(0);} getmaxsize(&breite,&hoehe,&tiefe,&visklasse); if(breite>XMAX) breite=XMAX; if(hoehe>YMAX) hoehe=YMAX; if(tiefe>TIEFE) tiefe=TIEFE; setsize(breite,hoehe,tiefe); setmenu(1,"File"); setmenu(1,"Exit",&menu_exit); inital(xmin,ymin,xmax,ymax); /* Grafikfenster oeffnen */ grafik_zeichnen(); term_refresh(); while(exitflag==0 && waitmenu(1)==0) ;// auf Benutzereingaben warten inital_new(); term_exit(); return 0; }// ende von mainWir wollen dieses also für die folgenden Beispiele als Stammprogramm verwenden.
Für die folgenden Programme werden wir dieses Stammprogramm fast unverändert übernehmen. Es wird dann einfach das Unterprogramm grafik_zeichnen() durch die wesentlichen Teile unseres Programms ersetzt, zusätzliche Menupunkte definiert und vielleicht in der Warteschlaufe noch was eingefügt.
Das makefile zu unserm Stammprogramm sieht so aus:
C=gcc -c -I$h -O3 L=c++ $h/xtekplot1.o -lm -lX11 -L/usr/X11R6/lib -O3 ## Amiga: #C=gcc -c -Ih: -DAMIGA -O3 #L=gcc -lm h:amitekplot1.o h:amigalib.a h:atan2.o -O3 all: grafikstart grafikstart: grafikstart.o $L grafikstart.o -o grafikstart grafikstart.o: grafikstart.cc $C grafikstart.cc clean: rm -f *.oDie Option -O3 veranlasst den Compiler zum optimieren, kann also auch weggelassen werden. Wenn der Debugger gdb benutzt werden soll, sollte -O3 durch -ggdb ersetzt werden.
Übung 8: Bringe das Stammprogramm auf deinem System zum laufen.
class Primzahl { int p; public: Primzahl() {p=2;} Primzahl(int zahl) {p=zahl;} int lesen() {return p;} int next(); int vorherige(); };Wie schon angedeutet können wir dann in unserm Beispielprogramm mit "Primzahl prim(1000);" die Variable direkt initialisieren und somit auf prim.setzen(1000) verzichten.
Ein neues Beispiel:
class Vector { double ko[2]; //ko[0]=x-Koordinate ko[1]=y-Koordinate public: Vector() {} Vector(double x,double y) {ko[0]=x; ko[1]=y;} double x() {return ko[0];} double y() {return ko[1];} };Für Vectoren beliebiger Grösse könnte es etwa so aussehen:
class Vector { double *ko; //ko[0]=x-Koordinate ko[1]=y-Koordinate int max; public: Vector() {ko=new double[max=2];} Vector(int n) {ko=new double[max=n];} Vector(double x,double y) {ko=new double[max=2]; ko[0]=x; ko[1]=y;} };Beim Beenden eines Objekts sollte man den mit new reservierten Speicher wieder freigeben. Dies kann man mit einem Destruktor realisieren . Einen Destruktor definiert man wieder als eine Typlose Funktion, wobei der Name ~Klassenname sein muss, in unserm Beispiel also:
~Vector() {delete[] ko;}Wenn wir mit unsern selbst definierten Klassen gleich wie mit gewöhnlichen Zahlen rechnen wollen, brauchen wir Operatoren die damit umgehen können.
double& operator[](int i) {return ko[i];} double operator=(Vector v) {ko[0]=v.ko[0]; ko[1]=v.ko[1];} double operator+=(Vector v) {ko[0] += v.ko[0]; v.ko[1] += v.ko[1];}Man beachte dass der Rückgabewert vom operator[] eine Referenz auf double ist, damit es wie gewohnt auch auf der linken Seite einer Zuweisung (L-Value) verwendet werden kann (also z.B. v[1]=y).
public: ... friend Vector operator+(Vector,Vector); }; Vector operator+(Vector v1,Vector v2) { Vector v; v.ko[0]=v1.ko[0]+v2.ko[0]; v.ko[1]=v1.ko[1]+v2.ko[1]; return v; }
class Kante { int k[2];//Indexe auf die Ecken public: void set(int a,int b) {k[0]=a; k[1]=b;} int a() {return k[0];} int b() {return k[1];} }; class Figur { int maxn,neck,nkant; Vector *eck; Kante *kant; public: Figur(int n); int getn() {return neck;} int ecke(double x,double y) {eck[neck]=Vector(x,y); return neck++;} int kante(int a,int b) {kant[nkant].set(a,b); return nkant++;} void zeichnen(int farbe=1); Vector& operator[](int i) {return eck[i];} }; Figur::Figur(int n) { int n2=n*n/2; eck=new Vector[maxn=n]; kant=new Kante[n2]; neck=0; nkant=0; } void linie(Vector a,Vector b) { plot(a[0],a[1],PENUP); plot(b[0],b[1],PENDOWN); } void Figur::zeichnen(int farbe) { for(int i=0;i<nkant;i++) {int a=kant[i].a(), b=kant[i].b(); linie(eck[a],eck[b]); } } static Figur dreieck(3);Jetzt sollten wir noch die Koordinaten der Ecken unseres Dreiecks setzen und die Kanten definieren. Wir könnten dies natürlich im Hauptprogramm etwa so machen:
dreieck.ecke(0,0); dreieck.ecke(1,0); dreieck.ecke(0,1); dreieck.kante(0,1); dreieck.kante(1,2); dreieck.kante(2,0);Eleganter wäre es aber wenn wir das im Konstruktor unserer Klasse machen könnten. Wir brauchen also eine Klasse Dreieck die mit der Klasse Figur identisch ist, aber dazu noch einen Konstruktor hat, dem wir die Koordinaten eines Dreiecks mitgeben können. Das kann mit einer Abgeleiteten Klasse realisiert werden:
class Dreieck:public Figur { public: Dreieck(double,double,double,double,double,double); }; Dreieck::Dreieck(double x1,double y1, double x2,double y2, double x3,double y3) : Figur(3) { ecke(x1,y1); ecke(x2,y2); ecke(x3,y3); kante(0,1); kante(1,2); kante(2,0); } static Dreieck dreieck(0,0, 1,0, 0,1);Mit :public wird also die Oberklasse (auch Basisklasse genannt) zur Klasse Dreieck definiert. Oder anders ausgedrückt: Dreieck ist eine von Figur abgeleitete Klasse.
Da sollte ich noch nachtragen dass es in Klassen ausser public:
noch folgende Schlüsselworte gibt:
private: ist alles was vor public: kommt,
protected: kann verwendet werden wenn abgeleitete Klassen
auch Zugriff haben sollen.
Um nicht alles abtippen zu müssen kann man hier das Dreieckbeispiel runterladen.
Übung 9: Vervollständige das Dreieckbeispiel so dass mehrere farbige Dreiecke gezeichnet werden. Oder vielleicht auch noch 4-Ecke, 5-Ecke ...