
/*
 * Listing4: © Clemens Marschner, 1994
 * Ein Beispiel zur Template-Verwendung und zu überladenen
 * Operatoren. Das Beispiel ist für jeden beliebigen Typ
 * verwendbar, auf dem die Operatoren '>' und '=' verwendet
 * werden können und die Stream-fähig sind.
 */

// sorttemplate.c; (W)94 by Clemens Marschner

#include <stream.h>	// cout...
#include <stdlib.h>	// rand()...
#include <time.h>
#include <string.h>	// strcpy()...
#include <stdio.h>	// getchar()

// eine generische Array-Klasse. Der Klassenbibliothek sind
// vollständige Versionen beigelegt (siehe classes/datastructures)

template <class T>	// T: beliebiger Platzhalter
class array {
	T *content;		// Zeiger auf Array vom Typ T
	int size;		// Größe des Arrays
public:
	// der Konstruktor mit Größe und Default-Werten
	array(int sz) { 
		content = new T[size = sz];
	}
	~array() { 
		delete[] content;
		// bei delete wird jeweils der Destruktor aufgerufen
		// delete[] ist für Arrays notwendig!
	}
	T& operator[](int index) {
		// gibt den Inhalt eines Arrayelements zurück
		return content[index];
	}
	int Size() { return size; }
};	

// eine einfache String-Klasse. Sie ist 
// vollständig in tools/str.h zu finden

class String {
	char*str;
public:
	void operator=(const char*s){ 
		// Zuweisungs-Operator: er verhindert, daß zwei 
		// String-Strukturen auf den gleichen String zeigen 
		// (Absturz bei delete!)
		str=new char[strlen(s)];
		strcpy(str, s);
	}
	
	String(const char*s=0) {
		if(s) operator=(s) else str=0l; 
	}

	~String() { delete str; }

	int operator>(const String&s) {
		return(strcmp(str, s.str) > 0 ? 1 : 0);
	}
	operator char*() { 
		// hiermit können String-Klassen wie normale
 		// String-Zeiger behandelt werden
		if(str) return str; 
		else return ""; 
	}
	friend ostream& operator << (ostream&, const 
String&);
};

// durch den überladenen Shift-Operator können Strings
// mit cout ausgegeben werden
ostream& operator << (ostream&o, const String&s) {
		return o << s.str;
}

// Template-Funktion, um den Inhalt zweier Typen zu vertauschen
template <class T>
void swap(T&a, T&b) {
	T c = a;			// langsam, da hier jeweils copy-
	a=b; b=c;		// Konstruktoren verwendet werden
}	

// Bubblesort - nicht schnell, aber einfach
template <class T> 
void sort(array<T>&ar) {
	for(int i=0; i<ar.Size()-1; i++) {
		for(int j=ar.Size()-1; i<j; j--) {
			if(ar[j-1] > ar[j])	
				swap(ar[j], ar[j-1]);	// typsicher!
		}
	}
}	

// jede Funktion, die mit Template-Parametern 
// hantiert, muß eine Template-Funktion sein:
template <class T> void PrintArray(array<T>&a) {
	for(int i=0; i<a.Size(); i++)  {
		cout << "a["<<i<<"]: "<<a[i]<<"\n";
		// bei *a vom Typ int wird hier der <<int-Operator
		// von ostream verwandt, bei String der eigene
	}
}

void main() {
	char *smp[] = {	"Meyer", "Hoffmann", "Holzmann",
							"Neumeister", "Schmid", "Peter", 
							"Werner", "Josef", "Günther", "Willi",
	};
	srand(time(0));

	array<String> a(9);	// ein Array aus String-Klassen
	for(int i=0; i<9; i++) {
		a[i] = smp[i];
		// Zuweisung: char* String via operator=
	}
	cout << "unsortiert:\n";	
	PrintArray(a);
	sort(a);
	cout << "\nsortiert:\n";
	PrintArray(a);			
	
	cout << "Taste: "; while(!getchar());
	
	array<int> b(10);
	for(i=0; i<10;i++){
		b[i] = rand();
	}
	cout << "\nints unsortiert:\n";
	PrintArray(b);
	cout << "\nints sortiert:\n";
	sort(b);
	PrintArray(b);
	
} // hier werden die Arrays destruiert


