# Template Klasse



## HolgerX (3. Mai 2004)

Hallo,
ich will in VS C++ 6.0 nen Template anlegen!

Leider gibt es nirgendwo die Funktion *Neues Template*  

Jetzt habe ich einfach eine neue Klasse angelegt und folgendes am Anfang der Headerdatei stehen: 
	
	
	



```
template <class T> class CBildMatrix  
{
```

Ausserdem werden dort die Variablen und Funktionen deklariert.
Die Implementierung habe ich dann wie gewohnt in die .cpp Datei geschrieben.
Beim Versuch den ganzen Kram zu kompilieren bekam ich folgende Fehlermeldung: 
	
	
	



```
Fuer die Verwendung einer Vorlagenklasse ist eine Vorlagen-Argumentliste erforderlich
```

In einem anderen Forum habe ich gelesen, dass auch die gesamte Implementierung in die .h Datei geschrieben werden muss.

Das habe ich dann auch getan und die .cpp gelöscht.

Aber wie kann ich nun in einer anderen Klasse mein Template nutzen?

Den Code habe ich aus einem Buch übernommen, dort stand dann folgender Aufruf: 
	
	
	



```
CBildMatrix<int> m1 (256,256);
```
Leider stand nirgendswo, wie ich das ausserhalb einer Main-Methode, z.B. in meiner Headerdatei der anderen Klasse als Membervariable aufrufen kann.

Jedenfalls schmeisst mir mein Kompiler immer Fehlermeldungen raus.


----------



## RedWing (3. Mai 2004)

also wenn du das Template in anderen Klassen nutzen willst dürfte
eine 


```
#include <template.h>

class Irgendwas{
      Template<int> member;
};
```

genügen um das Template als Membervariable zu nutzen.

2.) Wie hast du deine Methoden im Template definiert?

Eine Beispiel Methode sollte folgendes sein:


```
template<typename T> class Template{
   ...
  T& funktion(T& a, T& b){...}
   ...
}
```

Wenn du das alles befolgst sollte es eigentlich keine Probleme geben..

Gruß Redwing

p.S. Vielleicht kannst du auch Posten wie dein Template implementiert ist?


----------



## Kachelator (3. Mai 2004)

> Das habe ich dann auch getan und die .cpp gelöscht.


  Hm, Templates existieren in der Tat eigentlich nur in Headerdateien.  Sie sind ja auch keine Klassen oder Funktionen, sondern nur Vorlagen für Klassen oder Funktionen.

Was soll deine Templateklasse denn tun oder sein? Kannst du mal -- wie bereits angesprochen -- vorhandenen Code posten? Dann kann ich dir gerne helfen, das Ganze in die richtige Form zu bringen.

PS: Ich _liebe_ Templates!


----------



## HolgerX (4. Mai 2004)

So, hier habe ich mal den ollen Quelltext rüberkopiert, den ich aus dem Buch habe:
	
	
	



```
// BildMatrix.h: Schnittstelle für die Klasse CBildMatrix.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_BILDMATRIX_H__5E39E9A8_FDCC_4AAD_A55F_2E6EB09209C2__INCLUDED_)
#define AFX_BILDMATRIX_H__5E39E9A8_FDCC_4AAD_A55F_2E6EB09209C2__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

template <class T> class CBildMatrix  
{
	unsigned int m_iXsize, m_iYsize; // Größe der Matrix
	T ** m_Matrix;
public:
	CBildMatrix();
	CBildMatrix(const CBildMatrix&);
	CBildMatrix(int, int);
	virtual ~CBildMatrix();
	T* operator[] (int);			 // access to Vector
	void operator =	(const CBildMatrix&); //assign Matrix
	void operator = (const T& v);	 // assign v to each element
	const T* operator[] (int) const; // read only access
	operator T**() {return CBildMatrix); } //efficient access
	int GetSizeX() const {return m_iXsize; } 
	int GetSizeY() const {return m_iYsize; } 

};

#endif // !defined(AFX_BILDMATRIX_H__5E39E9A8_FDCC_4AAD_A55F_2E6EB09209C2__INCLUDED_)

template <class T> CBildMatrix<T>::CBildMatrix(int x, int y)
{
	m_iXsize = x;
	m_iYsize = y;
	T* array = new T[x*y];
	m_Matrix = new T*[y];
	for (int i = 0; i<y, ++i)
		m_Matrix[i] = & (array[i*x]); // fill in vector pointers
}

template <class T> T* CBildMatrix<T>::operator [](int i)
{
	return matrix [i];
}

template <class T> const T* CBildMatrix<T>::operator [] (int i) const
{
	return matrix[i];
}
```

Also 100%ig habe ich den Quelltext nicht übernommen, lediglich einige Bezeichnungen von Namen sind anders.
Außerdem sind noch die #if #endif Teile von VS drin.

Der Aufruf sollte dann folgendermaßen sein:
	
	
	



```
CBildMatrix<int> m1(256,256);
```
Wieso muss ich beim Nutzen von Templates eigentlich das #include mit in die Headerdatei der anderen Klasse (wo ich das Template nutzen will) schreiben, und nicht wie gewohnt in die .cpp Datei ?
Kann ich die Membervariable in der anderen Klasse nur deklarieren, ohne ihr einen Wert zuzuweisen? - Wie kann ich ihr dann innerhalb der .cpp Klasse einen Wert zuweisen?


----------



## Endurion (4. Mai 2004)

Ist m1ein Member einer anderen Klasse?

Dann musst du die Initialisierung in den Constructor eben dieser Klasse packen. 
Z.Bsp so:

Header:

```
class COberMotz
{
...

  COberMotz();

  CBuildMatrix<int> m1;
```

Cpp:

```
COberMotz::COberMotz() :
  m1( 256, 256 )
{
}
```

Damit wird der Constructor deiner Template-Klasse mit den beiden Parametern aufgerufen.


----------



## HolgerX (4. Mai 2004)

Das funktioniert sogar!  
Danke! 

Aber warum zum Geier müssen die Membervariablen so 
	
	
	



```
CPfurz::CPfurz() : m1(256,256)
{
}
```
 initialisiert werden? Und nicht einfach so:
	
	
	



```
CPfurz::CPfurz()
{
   m1(256,256);
}
```


----------



## Kachelator (4. Mai 2004)

Die erste Methode (mit Initialisierungsliste) ruft direkt den passenden Konstruktor auf, um dein Objekt zu initialisieren. Das ist sehr effektiv.

Bei der zweiten Version steht innerhalb deines Konstruktors ein Konstruktoraufruf für ein Objekt, das bereits vor Eintritt in den Konstruktor erzeugt worden ist (nämlich m1). Da kannst du nicht im Nachhinein noch mal einen Konstruktor aufrufen.


----------



## Daniel Toplak (4. Mai 2004)

Ja genau richtig, allerdings hat das mit Templates relativ wenig zu tun, denn das was Kachelator hier sagt, trifft allgemein auf Aggregationen von Objekten zu. (Aggregation kommt von UML)

Das ist eine Aggregation:

```
class A
{
public:
  A();
};

class B
{
public:
 B();
 A myA;  // hier eine Aggregation
}
```

Wie Kachelator schon sagte, wird das Objekt (myA)schon erzeugt bevor der Konstruktor von B durchlaufen wird.
Man kann das Ganze aber auch umgehen, in dem man einen Zeiger als Aggregation verwendet:

```
class A
{
public:
  A();
  A(int);
};

class B
{
public:
 B();
 ~B();
 A *myA;  // hier eine Aggregation allerdings "nur" als Zeiger auf A
}

B::B()
{
  myA = new A(5) // hier wird das Objekt erstellt
}

B::~B()
{
  delete myA;
}
```

So was hier passiert, ist, daß nur ein Zeiger deklariert wird, und *erst* der Kunstruktor von B aufgerufen wird und darin, dann der Kunstruktor von A, weil dort mit "new" erst das Objekt erzeugt wird.
Da dieses Objekt jetzt auf dem Heap-Speicher dynamisch erzeugt wird, muss man es natürlich auch wieder "selbst" löschen, sonst gibt es ein Speicherleck! Siehe Destruktor von B.

So ich hoffe das war etwas verständlich.

Gruß Homer


----------



## Bobbin (30. März 2005)

Hallo,

dazu benötige ich nochmal Hilfe: ich möchte ein Item anlegen mit einem Parameter eines gewünschten Typs. Dazu habe ich die Klasse Item und das template ItemValue. IM Item habe ich einen Pointer, auf den ich das entsprechende ItemValue legen will.

Das Template (ItemValue.h) sieht so aus:

```
template <class C> class ItemValue  
{
public:
	ItemValue();
//	virtual ~ItemValue();
	C value;
};
```


Mein Item (Item.h) sieht so aus:

```
#include "ItemValue.h"
class Item {
public:
	Item();
	void Get(int&);
	virtual ~Item();
private:
	int id;
	ItemValue *value;
};
typedef Item* pItem;
```

und die Item.cpp so:

```
#include "Item.h"

Item::Item() {}    //Constructor
Item::~Item() {}   //Destructor

void Item::Get(int& value)
{
	int lvalue = 0; 
	this->value =  new ItemValue <int>;

	this->value->value = lvalue;
}
```

Das geht aber leider nicht - der Typ stimmt nicht überein. Wie bekomme ich denn die Definition so hin, dass ich auf dem Pointer die Struktur zu liegen habe?

Gruß Bobbin.

_Der Code ist stark vereinfacht - bis auf die Probleme _


----------



## Endurion (30. März 2005)

Es gibt leider für Templates keine "Basisklasse" wie deinen ItemValue-Pointer.
Du müsstest dir da entweder ein Interface dazwischenschalten (frickelig) oder auf einen generell wandelbaren Typen gehen (oder sowas wie boost::any verwenden).

Ich war dann faul, und hab mir für einen Settings-Manager alles als String gespeichert. Bei ints oder floats wird dann einfach umgewandelt. Erspart einem eine Menge Ärger.


----------

